Fix merge
This commit is contained in:
commit
152fdbe024
@ -24,7 +24,7 @@ check-system-alpine:
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: alpine
|
||||
MAKE_CHECK_ARGS: check
|
||||
MAKE_CHECK_ARGS: check-unit check-qtest
|
||||
|
||||
avocado-system-alpine:
|
||||
extends: .avocado_test_job_template
|
||||
@ -164,7 +164,7 @@ build-system-centos:
|
||||
variables:
|
||||
IMAGE: centos8
|
||||
CONFIGURE_ARGS: --disable-nettle --enable-gcrypt --enable-fdt=system
|
||||
--enable-modules --enable-trace-backends=dtrace
|
||||
--enable-modules --enable-trace-backends=dtrace --enable-docs
|
||||
TARGETS: ppc64-softmmu or1k-softmmu s390x-softmmu
|
||||
x86_64-softmmu rx-softmmu sh4-softmmu nios2-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
|
@ -52,14 +52,11 @@ x64-freebsd-12-build:
|
||||
NAME: freebsd-12
|
||||
CIRRUS_VM_INSTANCE_TYPE: freebsd_instance
|
||||
CIRRUS_VM_IMAGE_SELECTOR: image_family
|
||||
CIRRUS_VM_IMAGE_NAME: freebsd-12-2
|
||||
CIRRUS_VM_IMAGE_NAME: freebsd-12-3
|
||||
CIRRUS_VM_CPUS: 8
|
||||
CIRRUS_VM_RAM: 8G
|
||||
UPDATE_COMMAND: pkg update
|
||||
INSTALL_COMMAND: pkg install -y
|
||||
# TODO: Enable gnutls again once FreeBSD's libtasn1 got fixed
|
||||
# See: https://gitlab.com/gnutls/libtasn1/-/merge_requests/71
|
||||
CONFIGURE_ARGS: --disable-gnutls
|
||||
TEST_TARGETS: check
|
||||
|
||||
x64-freebsd-13-build:
|
||||
|
@ -2,12 +2,15 @@
|
||||
#
|
||||
# $ lcitool variables freebsd-12 qemu
|
||||
#
|
||||
# https://gitlab.com/libvirt/libvirt-ci/-/commit/c7e275ab27ac0dcd09da290817b9adeea1fd1eb1
|
||||
# https://gitlab.com/libvirt/libvirt-ci
|
||||
|
||||
PACKAGING_COMMAND='pkg'
|
||||
CCACHE='/usr/local/bin/ccache'
|
||||
CPAN_PKGS=''
|
||||
CROSS_PKGS=''
|
||||
MAKE='/usr/local/bin/gmake'
|
||||
NINJA='/usr/local/bin/ninja'
|
||||
PYTHON='/usr/local/bin/python3'
|
||||
PACKAGING_COMMAND='pkg'
|
||||
PIP3='/usr/local/bin/pip-3.8'
|
||||
PKGS='alsa-lib bash bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage ctags curl cyrus-sasl dbus diffutils gettext git glib gmake gnutls gsed gtk3 libepoxy libffi libgcrypt libjpeg-turbo libnfs libspice-server libssh libtasn1 libxml2 llvm lttng-ust lzo2 meson ncurses nettle ninja opencv p5-Test-Harness perl5 pixman pkgconf png py38-numpy py38-pillow py38-pip py38-sphinx py38-sphinx_rtd_theme py38-virtualenv py38-yaml python3 rpm2cpio sdl2 sdl2_image snappy spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd'
|
||||
PKGS='alsa-lib bash bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage ctags curl cyrus-sasl dbus diffutils dtc gettext git glib gmake gnutls gsed gtk3 libepoxy libffi libgcrypt libjpeg-turbo libnfs libspice-server libssh libtasn1 libxml2 llvm lttng-ust lzo2 meson ncurses nettle ninja opencv p5-Test-Harness perl5 pixman pkgconf png py38-numpy py38-pillow py38-pip py38-sphinx py38-sphinx_rtd_theme py38-virtualenv py38-yaml python3 rpm2cpio sdl2 sdl2_image snappy spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd'
|
||||
PYPI_PKGS=''
|
||||
PYTHON='/usr/local/bin/python3'
|
||||
|
@ -2,12 +2,15 @@
|
||||
#
|
||||
# $ lcitool variables freebsd-13 qemu
|
||||
#
|
||||
# https://gitlab.com/libvirt/libvirt-ci/-/commit/c7e275ab27ac0dcd09da290817b9adeea1fd1eb1
|
||||
# https://gitlab.com/libvirt/libvirt-ci
|
||||
|
||||
PACKAGING_COMMAND='pkg'
|
||||
CCACHE='/usr/local/bin/ccache'
|
||||
CPAN_PKGS=''
|
||||
CROSS_PKGS=''
|
||||
MAKE='/usr/local/bin/gmake'
|
||||
NINJA='/usr/local/bin/ninja'
|
||||
PYTHON='/usr/local/bin/python3'
|
||||
PACKAGING_COMMAND='pkg'
|
||||
PIP3='/usr/local/bin/pip-3.8'
|
||||
PKGS='alsa-lib bash bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage ctags curl cyrus-sasl dbus diffutils gettext git glib gmake gnutls gsed gtk3 libepoxy libffi libgcrypt libjpeg-turbo libnfs libspice-server libssh libtasn1 libxml2 llvm lttng-ust lzo2 meson ncurses nettle ninja opencv p5-Test-Harness perl5 pixman pkgconf png py38-numpy py38-pillow py38-pip py38-sphinx py38-sphinx_rtd_theme py38-virtualenv py38-yaml python3 rpm2cpio sdl2 sdl2_image snappy spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd'
|
||||
PKGS='alsa-lib bash bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage ctags curl cyrus-sasl dbus diffutils dtc gettext git glib gmake gnutls gsed gtk3 libepoxy libffi libgcrypt libjpeg-turbo libnfs libspice-server libssh libtasn1 libxml2 llvm lttng-ust lzo2 meson ncurses nettle ninja opencv p5-Test-Harness perl5 pixman pkgconf png py38-numpy py38-pillow py38-pip py38-sphinx py38-sphinx_rtd_theme py38-virtualenv py38-yaml python3 rpm2cpio sdl2 sdl2_image snappy spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd'
|
||||
PYPI_PKGS=''
|
||||
PYTHON='/usr/local/bin/python3'
|
||||
|
@ -2,14 +2,15 @@
|
||||
#
|
||||
# $ lcitool variables macos-11 qemu
|
||||
#
|
||||
# https://gitlab.com/libvirt/libvirt-ci/-/commit/c7e275ab27ac0dcd09da290817b9adeea1fd1eb1
|
||||
# https://gitlab.com/libvirt/libvirt-ci
|
||||
|
||||
PACKAGING_COMMAND='brew'
|
||||
CCACHE='/usr/local/bin/ccache'
|
||||
CPAN_PKGS='Test::Harness'
|
||||
CROSS_PKGS=''
|
||||
MAKE='/usr/local/bin/gmake'
|
||||
NINJA='/usr/local/bin/ninja'
|
||||
PYTHON='/usr/local/bin/python3'
|
||||
PACKAGING_COMMAND='brew'
|
||||
PIP3='/usr/local/bin/pip3'
|
||||
PKGS='bash bc bzip2 capstone ccache cpanminus ctags curl dbus diffutils gcovr gettext git glib gnu-sed gnutls gtk+3 jemalloc jpeg-turbo libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb libxml2 llvm lzo make meson ncurses nettle ninja perl pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy sparse spice-protocol tesseract texinfo usbredir vde vte3 zlib zstd'
|
||||
PKGS='bash bc bzip2 capstone ccache cpanminus ctags curl dbus diffutils dtc gcovr gettext git glib gnu-sed gnutls gtk+3 jemalloc jpeg-turbo libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb libxml2 llvm lzo make meson ncurses nettle ninja perl pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy sparse spice-protocol tesseract texinfo usbredir vde vte3 zlib zstd'
|
||||
PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme virtualenv'
|
||||
CPAN_PKGS='Test::Harness'
|
||||
PYTHON='/usr/local/bin/python3'
|
||||
|
@ -29,11 +29,6 @@ amd64-ubuntu2004-container:
|
||||
variables:
|
||||
NAME: ubuntu2004
|
||||
|
||||
amd64-ubuntu-container:
|
||||
extends: .container_job_template
|
||||
variables:
|
||||
NAME: ubuntu
|
||||
|
||||
amd64-opensuse-leap-container:
|
||||
extends: .container_job_template
|
||||
variables:
|
||||
|
@ -3,7 +3,7 @@
|
||||
#
|
||||
FROM ubuntu:16.04
|
||||
|
||||
MAINTAINER Philippe Mathieu-Daudé <philmd@redhat.com>
|
||||
MAINTAINER Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||
|
||||
# Install packages required to build EDK2
|
||||
RUN apt update \
|
||||
|
@ -43,9 +43,7 @@ build-opensbi:
|
||||
artifacts:
|
||||
paths: # 'artifacts.zip' will contains the following files:
|
||||
- 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
|
||||
|
@ -46,4 +46,6 @@ check-python-tox:
|
||||
QEMU_TOX_EXTRA_ARGS: --skip-missing-interpreters=false
|
||||
needs:
|
||||
job: python-container
|
||||
rules:
|
||||
- when: manual
|
||||
allow_failure: true
|
||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -64,3 +64,6 @@
|
||||
[submodule "roms/vbootrom"]
|
||||
path = roms/vbootrom
|
||||
url = https://gitlab.com/qemu-project/vbootrom.git
|
||||
[submodule "tests/lcitool/libvirt-ci"]
|
||||
path = tests/lcitool/libvirt-ci
|
||||
url = http://gitlab.com/libvirt/libvirt-ci
|
||||
|
1
.mailmap
1
.mailmap
@ -63,6 +63,7 @@ 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>
|
||||
Philippe Mathieu-Daudé <f4bug@amsat.org> <philmd@redhat.com>
|
||||
Stefan Brankovic <stefan.brankovic@syrmia.com> <stefan.brankovic@rt-rk.com.com>
|
||||
Yongbok Kim <yongbok.kim@mips.com> <yongbok.kim@imgtec.com>
|
||||
|
||||
|
155
MAINTAINERS
155
MAINTAINERS
@ -297,7 +297,6 @@ M: David Hildenbrand <david@redhat.com>
|
||||
S: Maintained
|
||||
F: target/s390x/
|
||||
F: target/s390x/tcg
|
||||
F: target/s390x/cpu_models_*.[ch]
|
||||
F: hw/s390x/
|
||||
F: disas/s390.c
|
||||
F: tests/tcg/s390x/
|
||||
@ -396,16 +395,10 @@ M: Halil Pasic <pasic@linux.ibm.com>
|
||||
M: Christian Borntraeger <borntraeger@linux.ibm.com>
|
||||
S: Supported
|
||||
F: target/s390x/kvm/
|
||||
F: target/s390x/ioinst.[ch]
|
||||
F: target/s390x/machine.c
|
||||
F: target/s390x/sigp.c
|
||||
F: target/s390x/cpu_features*.[ch]
|
||||
F: target/s390x/cpu_models.[ch]
|
||||
F: hw/s390x/pv.c
|
||||
F: include/hw/s390x/pv.h
|
||||
F: hw/intc/s390_flic.c
|
||||
F: hw/intc/s390_flic_kvm.c
|
||||
F: include/hw/s390x/s390_flic.h
|
||||
F: gdb-xml/s390*.xml
|
||||
T: git https://github.com/borntraeger/qemu.git s390-next
|
||||
L: qemu-s390x@nongnu.org
|
||||
@ -781,6 +774,8 @@ M: Peter Maydell <peter.maydell@linaro.org>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Odd Fixes
|
||||
F: hw/arm/musicpal.c
|
||||
F: hw/net/mv88w8618_eth.c
|
||||
F: include/hw/net/mv88w8618_eth.h
|
||||
F: docs/system/arm/musicpal.rst
|
||||
|
||||
Nuvoton NPCM7xx
|
||||
@ -1245,7 +1240,7 @@ F: hw/openrisc/openrisc_sim.c
|
||||
|
||||
PowerPC Machines
|
||||
----------------
|
||||
405
|
||||
405 (ref405ep and taihu)
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Orphan
|
||||
F: hw/ppc/ppc405_boards.c
|
||||
@ -1281,6 +1276,7 @@ New World (mac99)
|
||||
M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Odd Fixes
|
||||
F: docs/system/ppc/powermac.rst
|
||||
F: hw/ppc/mac_newworld.c
|
||||
F: hw/pci-host/uninorth.c
|
||||
F: hw/pci-bridge/dec.[hc]
|
||||
@ -1299,6 +1295,7 @@ Old World (g3beige)
|
||||
M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Odd Fixes
|
||||
F: docs/system/ppc/powermac.rst
|
||||
F: hw/ppc/mac_oldworld.c
|
||||
F: hw/pci-host/grackle.c
|
||||
F: hw/misc/macio/
|
||||
@ -1312,6 +1309,7 @@ PReP
|
||||
M: Hervé Poussineau <hpoussin@reactos.org>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Maintained
|
||||
F: docs/system/ppc/prep.rst
|
||||
F: hw/ppc/prep.c
|
||||
F: hw/ppc/prep_systemio.c
|
||||
F: hw/ppc/rs6000_mc.c
|
||||
@ -1324,7 +1322,7 @@ F: include/hw/isa/pc87312.h
|
||||
F: include/hw/rtc/m48t59.h
|
||||
F: tests/avocado/ppc_prep_40p.py
|
||||
|
||||
sPAPR
|
||||
sPAPR (pseries)
|
||||
M: Cédric Le Goater <clg@kaod.org>
|
||||
M: Daniel Henrique Barboza <danielhb413@gmail.com>
|
||||
R: David Gibson <david@gibson.dropbear.id.au>
|
||||
@ -1336,8 +1334,8 @@ F: include/hw/*/spapr*
|
||||
F: hw/*/xics*
|
||||
F: include/hw/*/xics*
|
||||
F: pc-bios/slof.bin
|
||||
F: docs/specs/ppc-spapr-hcalls.txt
|
||||
F: docs/specs/ppc-spapr-hotplug.txt
|
||||
F: docs/system/ppc/pseries.rst
|
||||
F: docs/specs/ppc-spapr-*
|
||||
F: tests/qtest/spapr*
|
||||
F: tests/qtest/libqos/*spapr*
|
||||
F: tests/qtest/rtas*
|
||||
@ -1348,6 +1346,7 @@ PowerNV (Non-Virtualized)
|
||||
M: Cédric Le Goater <clg@kaod.org>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Maintained
|
||||
F: docs/system/ppc/powernv.rst
|
||||
F: hw/ppc/pnv*
|
||||
F: hw/intc/pnv*
|
||||
F: hw/intc/xics_pnv.c
|
||||
@ -1528,13 +1527,10 @@ S390 Machines
|
||||
S390 Virtio-ccw
|
||||
M: Halil Pasic <pasic@linux.ibm.com>
|
||||
M: Christian Borntraeger <borntraeger@linux.ibm.com>
|
||||
M: Eric Farman <farman@linux.ibm.com>
|
||||
S: Supported
|
||||
F: hw/char/sclp*.[hc]
|
||||
F: hw/char/terminal3270.c
|
||||
F: hw/s390x/
|
||||
F: include/hw/s390x/
|
||||
F: hw/watchdog/wdt_diag288.c
|
||||
F: include/hw/watchdog/wdt_diag288.h
|
||||
F: configs/devices/s390x-softmmu/default.mak
|
||||
F: tests/avocado/machine_s390_ccw_virtio.py
|
||||
T: git https://github.com/borntraeger/qemu.git s390-next
|
||||
@ -1559,6 +1555,38 @@ F: hw/s390x/s390-pci*
|
||||
F: include/hw/s390x/s390-pci*
|
||||
L: qemu-s390x@nongnu.org
|
||||
|
||||
S390 channel subsystem
|
||||
M: Halil Pasic <pasic@linux.ibm.com>
|
||||
M: Christian Borntraeger <borntraeger@linux.ibm.com>
|
||||
M: Eric Farman <farman@linux.ibm.com>
|
||||
S: Supported
|
||||
F: hw/s390x/ccw-device.[ch]
|
||||
F: hw/s390x/css.c
|
||||
F: hw/s390x/css-bridge.c
|
||||
F: include/hw/s390x/css.h
|
||||
F: include/hw/s390x/css-bridge.h
|
||||
F: include/hw/s390x/ioinst.h
|
||||
F: target/s390x/ioinst.c
|
||||
L: qemu-s390x@nongnu.org
|
||||
|
||||
S390 CPU models
|
||||
M: David Hildenbrand <david@redhat.com>
|
||||
S: Maintained
|
||||
F: target/s390x/cpu_features*.[ch]
|
||||
F: target/s390x/cpu_models.[ch]
|
||||
L: qemu-s390x@nongnu.org
|
||||
|
||||
S390 SCLP-backed devices
|
||||
M: Halil Pasic <pasic@linux.ibm.com>
|
||||
M: Christian Borntraeger <borntraeger@linux.ibm.com>
|
||||
S: Supported
|
||||
F: include/hw/s390x/event-facility.h
|
||||
F: include/hw/s390x/sclp.h
|
||||
F: hw/char/sclp*.[hc]
|
||||
F: hw/s390x/event-facility.c
|
||||
F: hw/s390x/sclp*.c
|
||||
L: qemu-s390x@nongnu.org
|
||||
|
||||
X86 Machines
|
||||
------------
|
||||
PC
|
||||
@ -1630,7 +1658,8 @@ F: pc-bios/bios-microvm.bin
|
||||
Machine core
|
||||
M: Eduardo Habkost <eduardo@habkost.net>
|
||||
M: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
|
||||
R: Philippe Mathieu-Daudé <philmd@redhat.com>
|
||||
R: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||
R: Yanan Wang <wangyanan55@huawei.com>
|
||||
S: Supported
|
||||
F: cpu.c
|
||||
F: hw/core/cpu.c
|
||||
@ -1776,6 +1805,13 @@ F: docs/specs/acpi_mem_hotplug.rst
|
||||
F: docs/specs/acpi_pci_hotplug.rst
|
||||
F: docs/specs/acpi_hw_reduced_hotplug.rst
|
||||
|
||||
ACPI/VIOT
|
||||
M: Jean-Philippe Brucker <jean-philippe@linaro.org>
|
||||
R: Ani Sinha <ani@anisinha.ca>
|
||||
S: Supported
|
||||
F: hw/acpi/viot.c
|
||||
F: hw/acpi/viot.h
|
||||
|
||||
ACPI/HEST/GHES
|
||||
R: Dongjiu Geng <gengdongjiu1@gmail.com>
|
||||
L: qemu-arm@nongnu.org
|
||||
@ -1810,7 +1846,7 @@ F: docs/virtio-net-failover.rst
|
||||
T: git https://github.com/jasowang/qemu.git net
|
||||
|
||||
Parallel NOR Flash devices
|
||||
M: Philippe Mathieu-Daudé <philmd@redhat.com>
|
||||
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||
T: git https://gitlab.com/philmd/qemu.git pflash-next
|
||||
S: Maintained
|
||||
F: hw/block/pflash_cfi*.c
|
||||
@ -1924,6 +1960,7 @@ virtio-balloon
|
||||
M: Michael S. Tsirkin <mst@redhat.com>
|
||||
M: David Hildenbrand <david@redhat.com>
|
||||
S: Maintained
|
||||
F: docs/interop/virtio-balloon-stats.rst
|
||||
F: hw/virtio/virtio-balloon*.c
|
||||
F: include/hw/virtio/virtio-balloon.h
|
||||
F: softmmu/balloon.c
|
||||
@ -1954,9 +1991,11 @@ T: git https://github.com/stefanha/qemu.git block
|
||||
virtio-ccw
|
||||
M: Cornelia Huck <cohuck@redhat.com>
|
||||
M: Halil Pasic <pasic@linux.ibm.com>
|
||||
M: Eric Farman <farman@linux.ibm.com>
|
||||
S: Supported
|
||||
F: hw/s390x/virtio-ccw*.[hc]
|
||||
F: hw/s390x/vhost-vsock-ccw.c
|
||||
F: hw/s390x/vhost-user-fs-ccw.c
|
||||
T: git https://gitlab.com/cohuck/qemu.git s390-next
|
||||
T: git https://github.com/borntraeger/qemu.git s390-next
|
||||
L: qemu-s390x@nongnu.org
|
||||
@ -2226,7 +2265,7 @@ F: hw/isa/piix4.c
|
||||
F: include/hw/southbridge/piix.h
|
||||
|
||||
Firmware configuration (fw_cfg)
|
||||
M: Philippe Mathieu-Daudé <philmd@redhat.com>
|
||||
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||
R: Gerd Hoffmann <kraxel@redhat.com>
|
||||
S: Supported
|
||||
F: docs/specs/fw_cfg.txt
|
||||
@ -2295,6 +2334,48 @@ F: hw/timer/mips_gictimer.c
|
||||
F: include/hw/intc/mips_gic.h
|
||||
F: include/hw/timer/mips_gictimer.h
|
||||
|
||||
S390 3270 device
|
||||
M: Halil Pasic <pasic@linux.ibm.com>
|
||||
M: Christian Borntraeger <borntraeger@linux.ibm.com>
|
||||
S: Odd fixes
|
||||
F: include/hw/s390x/3270-ccw.h
|
||||
F: hw/char/terminal3270.c
|
||||
F: hw/s390x/3270-ccw.c
|
||||
L: qemu-s390x@nongnu.org
|
||||
|
||||
S390 diag 288 watchdog
|
||||
M: Halil Pasic <pasic@linux.ibm.com>
|
||||
M: Christian Borntraeger <borntraeger@linux.ibm.com>
|
||||
S: Supported
|
||||
F: hw/watchdog/wdt_diag288.c
|
||||
F: include/hw/watchdog/wdt_diag288.h
|
||||
L: qemu-s390x@nongnu.org
|
||||
|
||||
S390 storage key device
|
||||
M: Halil Pasic <pasic@linux.ibm.com>
|
||||
M: Christian Borntraeger <borntraeger@linux.ibm.com>
|
||||
S: Supported
|
||||
F: hw/s390x/storage-keys.h
|
||||
F: hw/390x/s390-skeys*.c
|
||||
L: qemu-s390x@nongnu.org
|
||||
|
||||
S390 storage attribute device
|
||||
M: Halil Pasic <pasic@linux.ibm.com>
|
||||
M: Christian Borntraeger <borntraeger@linux.ibm.com>
|
||||
S: Supported
|
||||
F: hw/s390x/storage-attributes.h
|
||||
F: hw/s390/s390-stattrib*.c
|
||||
L: qemu-s390x@nongnu.org
|
||||
|
||||
S390 floating interrupt controller
|
||||
M: Halil Pasic <pasic@linux.ibm.com>
|
||||
M: Christian Borntraeger <borntraeger@linux.ibm.com>
|
||||
M: David Hildenbrand <david@redhat.com>
|
||||
S: Supported
|
||||
F: hw/intc/s390_flic*.c
|
||||
F: include/hw/s390x/s390_flic.h
|
||||
L: qemu-s390x@nongnu.org
|
||||
|
||||
Subsystems
|
||||
----------
|
||||
Overall Audio backends
|
||||
@ -2524,7 +2605,7 @@ F: scripts/coccinelle/errp-guard.cocci
|
||||
|
||||
GDB stub
|
||||
M: Alex Bennée <alex.bennee@linaro.org>
|
||||
R: Philippe Mathieu-Daudé <philmd@redhat.com>
|
||||
R: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||
S: Maintained
|
||||
F: gdbstub*
|
||||
F: include/exec/gdbstub.h
|
||||
@ -2535,7 +2616,7 @@ Memory API
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
M: Peter Xu <peterx@redhat.com>
|
||||
M: David Hildenbrand <david@redhat.com>
|
||||
R: Philippe Mathieu-Daudé <philmd@redhat.com>
|
||||
R: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||
S: Supported
|
||||
F: include/exec/ioport.h
|
||||
F: include/exec/memop.h
|
||||
@ -2728,6 +2809,14 @@ F: scripts/qemu-guest-agent/
|
||||
F: tests/unit/test-qga.c
|
||||
T: git https://github.com/mdroth/qemu.git qga
|
||||
|
||||
QEMU Guest Agent Win32
|
||||
M: Konstantin Kostiuk <kkostiuk@redhat.com>
|
||||
S: Maintained
|
||||
F: qga/*win32*
|
||||
F: qga/vss-win32/
|
||||
F: qga/installer/
|
||||
T: git https://github.com/kostyanf14/qemu.git qga-win32
|
||||
|
||||
QOM
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
R: Daniel P. Berrange <berrange@redhat.com>
|
||||
@ -2873,11 +2962,15 @@ D-Bus
|
||||
M: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
S: Maintained
|
||||
F: backends/dbus-vmstate.c
|
||||
F: tests/dbus-vmstate*
|
||||
F: ui/dbus*
|
||||
F: audio/dbus*
|
||||
F: util/dbus.c
|
||||
F: include/ui/dbus*
|
||||
F: include/qemu/dbus.h
|
||||
F: docs/interop/dbus.rst
|
||||
F: docs/interop/dbus-vmstate.rst
|
||||
F: docs/interop/dbus*
|
||||
F: docs/sphinx/dbus*
|
||||
F: docs/sphinx/fakedbusdoc.py
|
||||
F: tests/qtest/dbus*
|
||||
|
||||
Seccomp
|
||||
M: Eduardo Otubo <otubo@redhat.com>
|
||||
@ -2977,12 +3070,13 @@ F: docs/COLO-FT.txt
|
||||
|
||||
COLO Proxy
|
||||
M: Zhang Chen <chen.zhang@intel.com>
|
||||
M: Li Zhijian <lizhijian@cn.fujitsu.com>
|
||||
M: Li Zhijian <lizhijian@fujitsu.com>
|
||||
S: Supported
|
||||
F: docs/colo-proxy.txt
|
||||
F: net/colo*
|
||||
F: net/filter-rewriter.c
|
||||
F: net/filter-mirror.c
|
||||
F: tests/qtest/test-filter*
|
||||
|
||||
Record/replay
|
||||
M: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
|
||||
@ -3024,14 +3118,14 @@ F: include/hw/i2c/smbus_slave.h
|
||||
F: include/hw/i2c/smbus_eeprom.h
|
||||
|
||||
Firmware schema specifications
|
||||
M: Philippe Mathieu-Daudé <philmd@redhat.com>
|
||||
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||
R: Daniel P. Berrange <berrange@redhat.com>
|
||||
R: Kashyap Chamarthy <kchamart@redhat.com>
|
||||
S: Maintained
|
||||
F: docs/interop/firmware.json
|
||||
|
||||
EDK2 Firmware
|
||||
M: Philippe Mathieu-Daudé <philmd@redhat.com>
|
||||
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||
R: Gerd Hoffmann <kraxel@redhat.com>
|
||||
S: Supported
|
||||
F: hw/i386/*ovmf*
|
||||
@ -3139,6 +3233,11 @@ S: Maintained
|
||||
F: tcg/i386/
|
||||
F: disas/i386.c
|
||||
|
||||
LoongArch64 TCG target
|
||||
M: WANG Xuerui <git@xen0n.name>
|
||||
S: Maintained
|
||||
F: tcg/loongarch64/
|
||||
|
||||
MIPS TCG target
|
||||
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||
R: Aurelien Jarno <aurelien@aurel32.net>
|
||||
@ -3264,7 +3363,7 @@ F: block/null.c
|
||||
NVMe Block Driver
|
||||
M: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
R: Fam Zheng <fam@euphon.net>
|
||||
R: Philippe Mathieu-Daudé <philmd@redhat.com>
|
||||
R: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: block/nvme*
|
||||
@ -3507,7 +3606,7 @@ F: tests/tcg/Makefile.include
|
||||
Integration Testing with the Avocado framework
|
||||
W: https://trello.com/b/6Qi1pxVn/avocado-qemu
|
||||
R: Cleber Rosa <crosa@redhat.com>
|
||||
R: Philippe Mathieu-Daudé <philmd@redhat.com>
|
||||
R: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||
R: Wainer dos Santos Moschetta <wainersm@redhat.com>
|
||||
R: Beraldo Leal <bleal@redhat.com>
|
||||
S: Odd Fixes
|
||||
|
16
Makefile
16
Makefile
@ -145,7 +145,8 @@ NINJAFLAGS = $(if $V,-v) $(if $(MAKE.n), -n) $(if $(MAKE.k), -k0) \
|
||||
$(filter-out -j, $(lastword -j1 $(filter -l% -j%, $(MAKEFLAGS)))) \
|
||||
|
||||
ninja-cmd-goals = $(or $(MAKECMDGOALS), all)
|
||||
ninja-cmd-goals += $(foreach t, $(.tests), $(.test.deps.$t))
|
||||
ninja-cmd-goals += $(foreach t, $(.check.build-suites), $(.check-$t.deps))
|
||||
ninja-cmd-goals += $(foreach t, $(.bench.build-suites), $(.bench-$t.deps))
|
||||
|
||||
makefile-targets := build.ninja ctags TAGS cscope dist clean uninstall
|
||||
# "ninja -t targets" also lists all prerequisites. If build system
|
||||
@ -205,14 +206,11 @@ recurse-clean: $(addsuffix /clean, $(ROM_DIRS))
|
||||
clean: recurse-clean
|
||||
-$(quiet-@)test -f build.ninja && $(NINJA) $(NINJAFLAGS) -t clean || :
|
||||
-$(quiet-@)test -f build.ninja && $(NINJA) $(NINJAFLAGS) clean-ctlist || :
|
||||
# avoid old build problems by removing potentially incorrect old files
|
||||
rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
|
||||
find . \( -name '*.so' -o -name '*.dll' -o -name '*.[oda]' \) -type f \
|
||||
! -path ./roms/edk2/ArmPkg/Library/GccLto/liblto-aarch64.a \
|
||||
! -path ./roms/edk2/ArmPkg/Library/GccLto/liblto-arm.a \
|
||||
-exec rm {} +
|
||||
rm -f TAGS cscope.* *.pod *~ */*~
|
||||
rm -f fsdev/*.pod scsi/*.pod
|
||||
rm -f TAGS cscope.* *~ */*~
|
||||
|
||||
VERSION = $(shell cat $(SRC_PATH)/VERSION)
|
||||
|
||||
@ -223,10 +221,10 @@ qemu-%.tar.bz2:
|
||||
|
||||
distclean: clean
|
||||
-$(quiet-@)test -f build.ninja && $(NINJA) $(NINJAFLAGS) -t clean -g || :
|
||||
rm -f config-host.mak config-host.h* config-poison.h
|
||||
rm -f config-host.mak
|
||||
rm -f tests/tcg/config-*.mak
|
||||
rm -f config-all-disas.mak config.status
|
||||
rm -f roms/seabios/config.mak roms/vgabios/config.mak
|
||||
rm -f config.status
|
||||
rm -f roms/seabios/config.mak
|
||||
rm -f qemu-plugins-ld.symbols qemu-plugins-ld64.symbols
|
||||
rm -f *-config-target.h *-config-devices.mak *-config-devices.h
|
||||
rm -rf meson-private meson-logs meson-info compile_commands.json
|
||||
@ -287,6 +285,7 @@ cscope:
|
||||
# Needed by "meson install"
|
||||
export DESTDIR
|
||||
|
||||
include $(SRC_PATH)/tests/lcitool/Makefile.include
|
||||
include $(SRC_PATH)/tests/docker/Makefile.include
|
||||
include $(SRC_PATH)/tests/vm/Makefile.include
|
||||
|
||||
@ -316,6 +315,7 @@ endif
|
||||
@echo 'Test targets:'
|
||||
$(call print-help,check,Run all tests (check-help for details))
|
||||
$(call print-help,bench,Run all benchmarks)
|
||||
$(call print-help,lcitool-help,Help about targets for managing build environment manifests)
|
||||
$(call print-help,docker-help,Help about targets running tests inside containers)
|
||||
$(call print-help,vm-help,Help about targets running tests inside VM)
|
||||
@echo ''
|
||||
|
@ -1130,4 +1130,35 @@ HumanReadableText *qmp_x_query_opcount(Error **errp)
|
||||
return human_readable_text_from_str(buf);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROFILER
|
||||
|
||||
int64_t dev_time;
|
||||
|
||||
HumanReadableText *qmp_x_query_profile(Error **errp)
|
||||
{
|
||||
g_autoptr(GString) buf = g_string_new("");
|
||||
static int64_t last_cpu_exec_time;
|
||||
int64_t cpu_exec_time;
|
||||
int64_t delta;
|
||||
|
||||
cpu_exec_time = tcg_cpu_exec_time();
|
||||
delta = cpu_exec_time - last_cpu_exec_time;
|
||||
|
||||
g_string_append_printf(buf, "async time %" PRId64 " (%0.3f)\n",
|
||||
dev_time, dev_time / (double)NANOSECONDS_PER_SECOND);
|
||||
g_string_append_printf(buf, "qemu time %" PRId64 " (%0.3f)\n",
|
||||
delta, delta / (double)NANOSECONDS_PER_SECOND);
|
||||
last_cpu_exec_time = cpu_exec_time;
|
||||
dev_time = 0;
|
||||
|
||||
return human_readable_text_from_str(buf);
|
||||
}
|
||||
#else
|
||||
HumanReadableText *qmp_x_query_profile(Error **errp)
|
||||
{
|
||||
error_setg(errp, "Internal profiler not compiled");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
@ -1885,9 +1885,9 @@ load_memop(const void *haddr, MemOp op)
|
||||
return (uint32_t)ldl_be_p(haddr);
|
||||
case MO_LEUL:
|
||||
return (uint32_t)ldl_le_p(haddr);
|
||||
case MO_BEQ:
|
||||
case MO_BEUQ:
|
||||
return ldq_be_p(haddr);
|
||||
case MO_LEQ:
|
||||
case MO_LEUQ:
|
||||
return ldq_le_p(haddr);
|
||||
default:
|
||||
qemu_build_not_reached();
|
||||
@ -2081,16 +2081,16 @@ tcg_target_ulong helper_be_ldul_mmu(CPUArchState *env, target_ulong addr,
|
||||
uint64_t helper_le_ldq_mmu(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
validate_memop(oi, MO_LEQ);
|
||||
return load_helper(env, addr, oi, retaddr, MO_LEQ, false,
|
||||
validate_memop(oi, MO_LEUQ);
|
||||
return load_helper(env, addr, oi, retaddr, MO_LEUQ, false,
|
||||
helper_le_ldq_mmu);
|
||||
}
|
||||
|
||||
uint64_t helper_be_ldq_mmu(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
validate_memop(oi, MO_BEQ);
|
||||
return load_helper(env, addr, oi, retaddr, MO_BEQ, false,
|
||||
validate_memop(oi, MO_BEUQ);
|
||||
return load_helper(env, addr, oi, retaddr, MO_BEUQ, false,
|
||||
helper_be_ldq_mmu);
|
||||
}
|
||||
|
||||
@ -2166,7 +2166,7 @@ uint32_t cpu_ldl_be_mmu(CPUArchState *env, abi_ptr addr,
|
||||
uint64_t cpu_ldq_be_mmu(CPUArchState *env, abi_ptr addr,
|
||||
MemOpIdx oi, uintptr_t ra)
|
||||
{
|
||||
return cpu_load_helper(env, addr, oi, MO_BEQ, helper_be_ldq_mmu);
|
||||
return cpu_load_helper(env, addr, oi, MO_BEUQ, helper_be_ldq_mmu);
|
||||
}
|
||||
|
||||
uint16_t cpu_ldw_le_mmu(CPUArchState *env, abi_ptr addr,
|
||||
@ -2210,10 +2210,10 @@ store_memop(void *haddr, uint64_t val, MemOp op)
|
||||
case MO_LEUL:
|
||||
stl_le_p(haddr, val);
|
||||
break;
|
||||
case MO_BEQ:
|
||||
case MO_BEUQ:
|
||||
stq_be_p(haddr, val);
|
||||
break;
|
||||
case MO_LEQ:
|
||||
case MO_LEUQ:
|
||||
stq_le_p(haddr, val);
|
||||
break;
|
||||
default:
|
||||
@ -2465,15 +2465,15 @@ void helper_be_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val,
|
||||
void helper_le_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
validate_memop(oi, MO_LEQ);
|
||||
store_helper(env, addr, val, oi, retaddr, MO_LEQ);
|
||||
validate_memop(oi, MO_LEUQ);
|
||||
store_helper(env, addr, val, oi, retaddr, MO_LEUQ);
|
||||
}
|
||||
|
||||
void helper_be_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
validate_memop(oi, MO_BEQ);
|
||||
store_helper(env, addr, val, oi, retaddr, MO_BEQ);
|
||||
validate_memop(oi, MO_BEUQ);
|
||||
store_helper(env, addr, val, oi, retaddr, MO_BEUQ);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2609,11 +2609,11 @@ uint32_t cpu_ldl_code(CPUArchState *env, abi_ptr addr)
|
||||
static uint64_t full_ldq_code(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
return load_helper(env, addr, oi, retaddr, MO_TEQ, true, full_ldq_code);
|
||||
return load_helper(env, addr, oi, retaddr, MO_TEUQ, true, full_ldq_code);
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_TEQ, cpu_mmu_index(env, true));
|
||||
MemOpIdx oi = make_memop_idx(MO_TEUQ, cpu_mmu_index(env, true));
|
||||
return full_ldq_code(env, addr, oi, 0);
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ uint32_t cpu_ldl_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
uint64_t cpu_ldq_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_BEQ | MO_UNALN, mmu_idx);
|
||||
MemOpIdx oi = make_memop_idx(MO_BEUQ | MO_UNALN, mmu_idx);
|
||||
return cpu_ldq_be_mmu(env, addr, oi, ra);
|
||||
}
|
||||
|
||||
@ -72,7 +72,7 @@ uint32_t cpu_ldl_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
uint64_t cpu_ldq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_LEQ | MO_UNALN, mmu_idx);
|
||||
MemOpIdx oi = make_memop_idx(MO_LEUQ | MO_UNALN, mmu_idx);
|
||||
return cpu_ldq_le_mmu(env, addr, oi, ra);
|
||||
}
|
||||
|
||||
@ -100,7 +100,7 @@ void cpu_stl_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
|
||||
void cpu_stq_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint64_t val,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_BEQ | MO_UNALN, mmu_idx);
|
||||
MemOpIdx oi = make_memop_idx(MO_BEUQ | MO_UNALN, mmu_idx);
|
||||
cpu_stq_be_mmu(env, addr, val, oi, ra);
|
||||
}
|
||||
|
||||
@ -121,7 +121,7 @@ void cpu_stl_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
|
||||
void cpu_stq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint64_t val,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_LEQ | MO_UNALN, mmu_idx);
|
||||
MemOpIdx oi = make_memop_idx(MO_LEUQ | MO_UNALN, mmu_idx);
|
||||
cpu_stq_le_mmu(env, addr, val, oi, ra);
|
||||
}
|
||||
|
||||
|
@ -294,7 +294,7 @@ uint64_t cpu_ldq_be_mmu(CPUArchState *env, abi_ptr addr,
|
||||
void *haddr;
|
||||
uint64_t ret;
|
||||
|
||||
validate_memop(oi, MO_BEQ);
|
||||
validate_memop(oi, MO_BEUQ);
|
||||
trace_guest_ld_before_exec(env_cpu(env), addr, oi);
|
||||
haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_LOAD);
|
||||
ret = ldq_be_p(haddr);
|
||||
@ -339,7 +339,7 @@ uint64_t cpu_ldq_le_mmu(CPUArchState *env, abi_ptr addr,
|
||||
void *haddr;
|
||||
uint64_t ret;
|
||||
|
||||
validate_memop(oi, MO_LEQ);
|
||||
validate_memop(oi, MO_LEUQ);
|
||||
trace_guest_ld_before_exec(env_cpu(env), addr, oi);
|
||||
haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_LOAD);
|
||||
ret = ldq_le_p(haddr);
|
||||
@ -392,7 +392,7 @@ void cpu_stq_be_mmu(CPUArchState *env, abi_ptr addr, uint64_t val,
|
||||
{
|
||||
void *haddr;
|
||||
|
||||
validate_memop(oi, MO_BEQ);
|
||||
validate_memop(oi, MO_BEUQ);
|
||||
trace_guest_st_before_exec(env_cpu(env), addr, oi);
|
||||
haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE);
|
||||
stq_be_p(haddr, val);
|
||||
@ -431,7 +431,7 @@ void cpu_stq_le_mmu(CPUArchState *env, abi_ptr addr, uint64_t val,
|
||||
{
|
||||
void *haddr;
|
||||
|
||||
validate_memop(oi, MO_LEQ);
|
||||
validate_memop(oi, MO_LEUQ);
|
||||
trace_guest_st_before_exec(env_cpu(env), addr, oi);
|
||||
haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE);
|
||||
stq_le_p(haddr, val);
|
||||
|
@ -2000,6 +2000,7 @@ void audio_create_pdos(Audiodev *dev)
|
||||
CASE(NONE, none, );
|
||||
CASE(ALSA, alsa, Alsa);
|
||||
CASE(COREAUDIO, coreaudio, Coreaudio);
|
||||
CASE(DBUS, dbus, );
|
||||
CASE(DSOUND, dsound, );
|
||||
CASE(JACK, jack, Jack);
|
||||
CASE(OSS, oss, Oss);
|
||||
|
@ -31,6 +31,10 @@
|
||||
#endif
|
||||
#include "mixeng.h"
|
||||
|
||||
#ifdef CONFIG_GIO
|
||||
#include <gio/gio.h>
|
||||
#endif
|
||||
|
||||
struct audio_pcm_ops;
|
||||
|
||||
struct audio_callback {
|
||||
@ -140,6 +144,9 @@ struct audio_driver {
|
||||
const char *descr;
|
||||
void *(*init) (Audiodev *);
|
||||
void (*fini) (void *);
|
||||
#ifdef CONFIG_GIO
|
||||
void (*set_dbus_server) (AudioState *s, GDBusObjectManagerServer *manager);
|
||||
#endif
|
||||
struct audio_pcm_ops *pcm_ops;
|
||||
int can_be_default;
|
||||
int max_voices_out;
|
||||
|
@ -327,6 +327,8 @@ AudiodevPerDirectionOptions *glue(audio_get_pdo_, TYPE)(Audiodev *dev)
|
||||
case AUDIODEV_DRIVER_COREAUDIO:
|
||||
return qapi_AudiodevCoreaudioPerDirectionOptions_base(
|
||||
dev->u.coreaudio.TYPE);
|
||||
case AUDIODEV_DRIVER_DBUS:
|
||||
return dev->u.dbus.TYPE;
|
||||
case AUDIODEV_DRIVER_DSOUND:
|
||||
return dev->u.dsound.TYPE;
|
||||
case AUDIODEV_DRIVER_JACK:
|
||||
|
654
audio/dbusaudio.c
Normal file
654
audio/dbusaudio.c
Normal file
@ -0,0 +1,654 @@
|
||||
/*
|
||||
* QEMU DBus audio
|
||||
*
|
||||
* Copyright (c) 2021 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/dbus.h"
|
||||
|
||||
#include <gio/gunixfdlist.h>
|
||||
#include "ui/dbus-display1.h"
|
||||
|
||||
#define AUDIO_CAP "dbus"
|
||||
#include "audio.h"
|
||||
#include "audio_int.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define DBUS_DISPLAY1_AUDIO_PATH DBUS_DISPLAY1_ROOT "/Audio"
|
||||
|
||||
#define DBUS_AUDIO_NSAMPLES 1024 /* could be configured? */
|
||||
|
||||
typedef struct DBusAudio {
|
||||
GDBusObjectManagerServer *server;
|
||||
GDBusObjectSkeleton *audio;
|
||||
QemuDBusDisplay1Audio *iface;
|
||||
GHashTable *out_listeners;
|
||||
GHashTable *in_listeners;
|
||||
} DBusAudio;
|
||||
|
||||
typedef struct DBusVoiceOut {
|
||||
HWVoiceOut hw;
|
||||
bool enabled;
|
||||
RateCtl rate;
|
||||
|
||||
void *buf;
|
||||
size_t buf_pos;
|
||||
size_t buf_size;
|
||||
|
||||
bool has_volume;
|
||||
Volume volume;
|
||||
} DBusVoiceOut;
|
||||
|
||||
typedef struct DBusVoiceIn {
|
||||
HWVoiceIn hw;
|
||||
bool enabled;
|
||||
RateCtl rate;
|
||||
|
||||
bool has_volume;
|
||||
Volume volume;
|
||||
} DBusVoiceIn;
|
||||
|
||||
static void *dbus_get_buffer_out(HWVoiceOut *hw, size_t *size)
|
||||
{
|
||||
DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
|
||||
|
||||
if (!vo->buf) {
|
||||
vo->buf_size = hw->samples * hw->info.bytes_per_frame;
|
||||
vo->buf = g_malloc(vo->buf_size);
|
||||
vo->buf_pos = 0;
|
||||
}
|
||||
|
||||
*size = MIN(vo->buf_size - vo->buf_pos, *size);
|
||||
*size = audio_rate_get_bytes(&hw->info, &vo->rate, *size);
|
||||
|
||||
return vo->buf + vo->buf_pos;
|
||||
|
||||
}
|
||||
|
||||
static size_t dbus_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
|
||||
{
|
||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
||||
DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
|
||||
GHashTableIter iter;
|
||||
QemuDBusDisplay1AudioOutListener *listener = NULL;
|
||||
g_autoptr(GBytes) bytes = NULL;
|
||||
g_autoptr(GVariant) v_data = NULL;
|
||||
|
||||
assert(buf == vo->buf + vo->buf_pos && vo->buf_pos + size <= vo->buf_size);
|
||||
vo->buf_pos += size;
|
||||
|
||||
trace_dbus_audio_put_buffer_out(size);
|
||||
|
||||
if (vo->buf_pos < vo->buf_size) {
|
||||
return size;
|
||||
}
|
||||
|
||||
bytes = g_bytes_new_take(g_steal_pointer(&vo->buf), vo->buf_size);
|
||||
v_data = g_variant_new_from_bytes(G_VARIANT_TYPE("ay"), bytes, TRUE);
|
||||
g_variant_ref_sink(v_data);
|
||||
|
||||
g_hash_table_iter_init(&iter, da->out_listeners);
|
||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
||||
qemu_dbus_display1_audio_out_listener_call_write(
|
||||
listener,
|
||||
(uintptr_t)hw,
|
||||
v_data,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
#define AUDIO_HOST_BE TRUE
|
||||
#else
|
||||
#define AUDIO_HOST_BE FALSE
|
||||
#endif
|
||||
|
||||
static void
|
||||
dbus_init_out_listener(QemuDBusDisplay1AudioOutListener *listener,
|
||||
HWVoiceOut *hw)
|
||||
{
|
||||
qemu_dbus_display1_audio_out_listener_call_init(
|
||||
listener,
|
||||
(uintptr_t)hw,
|
||||
hw->info.bits,
|
||||
hw->info.is_signed,
|
||||
hw->info.is_float,
|
||||
hw->info.freq,
|
||||
hw->info.nchannels,
|
||||
hw->info.bytes_per_frame,
|
||||
hw->info.bytes_per_second,
|
||||
hw->info.swap_endianness ? !AUDIO_HOST_BE : AUDIO_HOST_BE,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
dbus_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque)
|
||||
{
|
||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
||||
DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
|
||||
GHashTableIter iter;
|
||||
QemuDBusDisplay1AudioOutListener *listener = NULL;
|
||||
|
||||
audio_pcm_init_info(&hw->info, as);
|
||||
hw->samples = DBUS_AUDIO_NSAMPLES;
|
||||
audio_rate_start(&vo->rate);
|
||||
|
||||
g_hash_table_iter_init(&iter, da->out_listeners);
|
||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
||||
dbus_init_out_listener(listener, hw);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_fini_out(HWVoiceOut *hw)
|
||||
{
|
||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
||||
DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
|
||||
GHashTableIter iter;
|
||||
QemuDBusDisplay1AudioOutListener *listener = NULL;
|
||||
|
||||
g_hash_table_iter_init(&iter, da->out_listeners);
|
||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
||||
qemu_dbus_display1_audio_out_listener_call_fini(
|
||||
listener,
|
||||
(uintptr_t)hw,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
g_clear_pointer(&vo->buf, g_free);
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_enable_out(HWVoiceOut *hw, bool enable)
|
||||
{
|
||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
||||
DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
|
||||
GHashTableIter iter;
|
||||
QemuDBusDisplay1AudioOutListener *listener = NULL;
|
||||
|
||||
vo->enabled = enable;
|
||||
if (enable) {
|
||||
audio_rate_start(&vo->rate);
|
||||
}
|
||||
|
||||
g_hash_table_iter_init(&iter, da->out_listeners);
|
||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
||||
qemu_dbus_display1_audio_out_listener_call_set_enabled(
|
||||
listener, (uintptr_t)hw, enable,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_volume_out_listener(HWVoiceOut *hw,
|
||||
QemuDBusDisplay1AudioOutListener *listener)
|
||||
{
|
||||
DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
|
||||
Volume *vol = &vo->volume;
|
||||
g_autoptr(GBytes) bytes = NULL;
|
||||
GVariant *v_vol = NULL;
|
||||
|
||||
if (!vo->has_volume) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(vol->channels < sizeof(vol->vol));
|
||||
bytes = g_bytes_new(vol->vol, vol->channels);
|
||||
v_vol = g_variant_new_from_bytes(G_VARIANT_TYPE("ay"), bytes, TRUE);
|
||||
qemu_dbus_display1_audio_out_listener_call_set_volume(
|
||||
listener, (uintptr_t)hw, vol->mute, v_vol,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_volume_out(HWVoiceOut *hw, Volume *vol)
|
||||
{
|
||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
||||
DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
|
||||
GHashTableIter iter;
|
||||
QemuDBusDisplay1AudioOutListener *listener = NULL;
|
||||
|
||||
vo->has_volume = true;
|
||||
vo->volume = *vol;
|
||||
|
||||
g_hash_table_iter_init(&iter, da->out_listeners);
|
||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
||||
dbus_volume_out_listener(hw, listener);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_init_in_listener(QemuDBusDisplay1AudioInListener *listener, HWVoiceIn *hw)
|
||||
{
|
||||
qemu_dbus_display1_audio_in_listener_call_init(
|
||||
listener,
|
||||
(uintptr_t)hw,
|
||||
hw->info.bits,
|
||||
hw->info.is_signed,
|
||||
hw->info.is_float,
|
||||
hw->info.freq,
|
||||
hw->info.nchannels,
|
||||
hw->info.bytes_per_frame,
|
||||
hw->info.bytes_per_second,
|
||||
hw->info.swap_endianness ? !AUDIO_HOST_BE : AUDIO_HOST_BE,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
dbus_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
|
||||
{
|
||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
||||
DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw);
|
||||
GHashTableIter iter;
|
||||
QemuDBusDisplay1AudioInListener *listener = NULL;
|
||||
|
||||
audio_pcm_init_info(&hw->info, as);
|
||||
hw->samples = DBUS_AUDIO_NSAMPLES;
|
||||
audio_rate_start(&vo->rate);
|
||||
|
||||
g_hash_table_iter_init(&iter, da->in_listeners);
|
||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
||||
dbus_init_in_listener(listener, hw);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_fini_in(HWVoiceIn *hw)
|
||||
{
|
||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
||||
GHashTableIter iter;
|
||||
QemuDBusDisplay1AudioInListener *listener = NULL;
|
||||
|
||||
g_hash_table_iter_init(&iter, da->in_listeners);
|
||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
||||
qemu_dbus_display1_audio_in_listener_call_fini(
|
||||
listener,
|
||||
(uintptr_t)hw,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_volume_in_listener(HWVoiceIn *hw,
|
||||
QemuDBusDisplay1AudioInListener *listener)
|
||||
{
|
||||
DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw);
|
||||
Volume *vol = &vo->volume;
|
||||
g_autoptr(GBytes) bytes = NULL;
|
||||
GVariant *v_vol = NULL;
|
||||
|
||||
if (!vo->has_volume) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(vol->channels < sizeof(vol->vol));
|
||||
bytes = g_bytes_new(vol->vol, vol->channels);
|
||||
v_vol = g_variant_new_from_bytes(G_VARIANT_TYPE("ay"), bytes, TRUE);
|
||||
qemu_dbus_display1_audio_in_listener_call_set_volume(
|
||||
listener, (uintptr_t)hw, vol->mute, v_vol,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_volume_in(HWVoiceIn *hw, Volume *vol)
|
||||
{
|
||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
||||
DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw);
|
||||
GHashTableIter iter;
|
||||
QemuDBusDisplay1AudioInListener *listener = NULL;
|
||||
|
||||
vo->has_volume = true;
|
||||
vo->volume = *vol;
|
||||
|
||||
g_hash_table_iter_init(&iter, da->in_listeners);
|
||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
||||
dbus_volume_in_listener(hw, listener);
|
||||
}
|
||||
}
|
||||
|
||||
static size_t
|
||||
dbus_read(HWVoiceIn *hw, void *buf, size_t size)
|
||||
{
|
||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
||||
/* DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw); */
|
||||
GHashTableIter iter;
|
||||
QemuDBusDisplay1AudioInListener *listener = NULL;
|
||||
|
||||
trace_dbus_audio_read(size);
|
||||
|
||||
/* size = audio_rate_get_bytes(&hw->info, &vo->rate, size); */
|
||||
|
||||
g_hash_table_iter_init(&iter, da->in_listeners);
|
||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
||||
g_autoptr(GVariant) v_data = NULL;
|
||||
const char *data;
|
||||
gsize n = 0;
|
||||
|
||||
if (qemu_dbus_display1_audio_in_listener_call_read_sync(
|
||||
listener,
|
||||
(uintptr_t)hw,
|
||||
size,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1,
|
||||
&v_data, NULL, NULL)) {
|
||||
data = g_variant_get_fixed_array(v_data, &n, 1);
|
||||
g_warn_if_fail(n <= size);
|
||||
size = MIN(n, size);
|
||||
memcpy(buf, data, size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_enable_in(HWVoiceIn *hw, bool enable)
|
||||
{
|
||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
||||
DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw);
|
||||
GHashTableIter iter;
|
||||
QemuDBusDisplay1AudioInListener *listener = NULL;
|
||||
|
||||
vo->enabled = enable;
|
||||
if (enable) {
|
||||
audio_rate_start(&vo->rate);
|
||||
}
|
||||
|
||||
g_hash_table_iter_init(&iter, da->in_listeners);
|
||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
||||
qemu_dbus_display1_audio_in_listener_call_set_enabled(
|
||||
listener, (uintptr_t)hw, enable,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void *
|
||||
dbus_audio_init(Audiodev *dev)
|
||||
{
|
||||
DBusAudio *da = g_new0(DBusAudio, 1);
|
||||
|
||||
da->out_listeners = g_hash_table_new_full(g_str_hash, g_str_equal,
|
||||
g_free, g_object_unref);
|
||||
da->in_listeners = g_hash_table_new_full(g_str_hash, g_str_equal,
|
||||
g_free, g_object_unref);
|
||||
return da;
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_audio_fini(void *opaque)
|
||||
{
|
||||
DBusAudio *da = opaque;
|
||||
|
||||
if (da->server) {
|
||||
g_dbus_object_manager_server_unexport(da->server,
|
||||
DBUS_DISPLAY1_AUDIO_PATH);
|
||||
}
|
||||
g_clear_object(&da->audio);
|
||||
g_clear_object(&da->iface);
|
||||
g_clear_pointer(&da->in_listeners, g_hash_table_unref);
|
||||
g_clear_pointer(&da->out_listeners, g_hash_table_unref);
|
||||
g_clear_object(&da->server);
|
||||
g_free(da);
|
||||
}
|
||||
|
||||
static void
|
||||
listener_out_vanished_cb(GDBusConnection *connection,
|
||||
gboolean remote_peer_vanished,
|
||||
GError *error,
|
||||
DBusAudio *da)
|
||||
{
|
||||
char *name = g_object_get_data(G_OBJECT(connection), "name");
|
||||
|
||||
g_hash_table_remove(da->out_listeners, name);
|
||||
}
|
||||
|
||||
static void
|
||||
listener_in_vanished_cb(GDBusConnection *connection,
|
||||
gboolean remote_peer_vanished,
|
||||
GError *error,
|
||||
DBusAudio *da)
|
||||
{
|
||||
char *name = g_object_get_data(G_OBJECT(connection), "name");
|
||||
|
||||
g_hash_table_remove(da->in_listeners, name);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
dbus_audio_register_listener(AudioState *s,
|
||||
GDBusMethodInvocation *invocation,
|
||||
GUnixFDList *fd_list,
|
||||
GVariant *arg_listener,
|
||||
bool out)
|
||||
{
|
||||
DBusAudio *da = s->drv_opaque;
|
||||
const char *sender = g_dbus_method_invocation_get_sender(invocation);
|
||||
g_autoptr(GDBusConnection) listener_conn = NULL;
|
||||
g_autoptr(GError) err = NULL;
|
||||
g_autoptr(GSocket) socket = NULL;
|
||||
g_autoptr(GSocketConnection) socket_conn = NULL;
|
||||
g_autofree char *guid = g_dbus_generate_guid();
|
||||
GHashTable *listeners = out ? da->out_listeners : da->in_listeners;
|
||||
GObject *listener;
|
||||
int fd;
|
||||
|
||||
trace_dbus_audio_register(sender, out ? "out" : "in");
|
||||
|
||||
if (g_hash_table_contains(listeners, sender)) {
|
||||
g_dbus_method_invocation_return_error(invocation,
|
||||
DBUS_DISPLAY_ERROR,
|
||||
DBUS_DISPLAY_ERROR_INVALID,
|
||||
"`%s` is already registered!",
|
||||
sender);
|
||||
return DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
||||
fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(arg_listener), &err);
|
||||
if (err) {
|
||||
g_dbus_method_invocation_return_error(invocation,
|
||||
DBUS_DISPLAY_ERROR,
|
||||
DBUS_DISPLAY_ERROR_FAILED,
|
||||
"Couldn't get peer fd: %s",
|
||||
err->message);
|
||||
return DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
||||
socket = g_socket_new_from_fd(fd, &err);
|
||||
if (err) {
|
||||
g_dbus_method_invocation_return_error(invocation,
|
||||
DBUS_DISPLAY_ERROR,
|
||||
DBUS_DISPLAY_ERROR_FAILED,
|
||||
"Couldn't make a socket: %s",
|
||||
err->message);
|
||||
return DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
socket_conn = g_socket_connection_factory_create_connection(socket);
|
||||
if (out) {
|
||||
qemu_dbus_display1_audio_complete_register_out_listener(
|
||||
da->iface, invocation, NULL);
|
||||
} else {
|
||||
qemu_dbus_display1_audio_complete_register_in_listener(
|
||||
da->iface, invocation, NULL);
|
||||
}
|
||||
|
||||
listener_conn =
|
||||
g_dbus_connection_new_sync(
|
||||
G_IO_STREAM(socket_conn),
|
||||
guid,
|
||||
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER,
|
||||
NULL, NULL, &err);
|
||||
if (err) {
|
||||
error_report("Failed to setup peer connection: %s", err->message);
|
||||
return DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
||||
listener = out ?
|
||||
G_OBJECT(qemu_dbus_display1_audio_out_listener_proxy_new_sync(
|
||||
listener_conn,
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
|
||||
NULL,
|
||||
"/org/qemu/Display1/AudioOutListener",
|
||||
NULL,
|
||||
&err)) :
|
||||
G_OBJECT(qemu_dbus_display1_audio_in_listener_proxy_new_sync(
|
||||
listener_conn,
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
|
||||
NULL,
|
||||
"/org/qemu/Display1/AudioInListener",
|
||||
NULL,
|
||||
&err));
|
||||
if (!listener) {
|
||||
error_report("Failed to setup proxy: %s", err->message);
|
||||
return DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
||||
if (out) {
|
||||
HWVoiceOut *hw;
|
||||
|
||||
QLIST_FOREACH(hw, &s->hw_head_out, entries) {
|
||||
DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
|
||||
QemuDBusDisplay1AudioOutListener *l =
|
||||
QEMU_DBUS_DISPLAY1_AUDIO_OUT_LISTENER(listener);
|
||||
|
||||
dbus_init_out_listener(l, hw);
|
||||
qemu_dbus_display1_audio_out_listener_call_set_enabled(
|
||||
l, (uintptr_t)hw, vo->enabled,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
||||
}
|
||||
} else {
|
||||
HWVoiceIn *hw;
|
||||
|
||||
QLIST_FOREACH(hw, &s->hw_head_in, entries) {
|
||||
DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw);
|
||||
QemuDBusDisplay1AudioInListener *l =
|
||||
QEMU_DBUS_DISPLAY1_AUDIO_IN_LISTENER(listener);
|
||||
|
||||
dbus_init_in_listener(
|
||||
QEMU_DBUS_DISPLAY1_AUDIO_IN_LISTENER(listener), hw);
|
||||
qemu_dbus_display1_audio_in_listener_call_set_enabled(
|
||||
l, (uintptr_t)hw, vo->enabled,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
g_object_set_data_full(G_OBJECT(listener_conn), "name",
|
||||
g_strdup(sender), g_free);
|
||||
g_hash_table_insert(listeners, g_strdup(sender), listener);
|
||||
g_object_connect(listener_conn,
|
||||
"signal::closed",
|
||||
out ? listener_out_vanished_cb : listener_in_vanished_cb,
|
||||
da,
|
||||
NULL);
|
||||
|
||||
return DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
dbus_audio_register_out_listener(AudioState *s,
|
||||
GDBusMethodInvocation *invocation,
|
||||
GUnixFDList *fd_list,
|
||||
GVariant *arg_listener)
|
||||
{
|
||||
return dbus_audio_register_listener(s, invocation,
|
||||
fd_list, arg_listener, true);
|
||||
|
||||
}
|
||||
|
||||
static gboolean
|
||||
dbus_audio_register_in_listener(AudioState *s,
|
||||
GDBusMethodInvocation *invocation,
|
||||
GUnixFDList *fd_list,
|
||||
GVariant *arg_listener)
|
||||
{
|
||||
return dbus_audio_register_listener(s, invocation,
|
||||
fd_list, arg_listener, false);
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_audio_set_server(AudioState *s, GDBusObjectManagerServer *server)
|
||||
{
|
||||
DBusAudio *da = s->drv_opaque;
|
||||
|
||||
g_assert(da);
|
||||
g_assert(!da->server);
|
||||
|
||||
da->server = g_object_ref(server);
|
||||
|
||||
da->audio = g_dbus_object_skeleton_new(DBUS_DISPLAY1_AUDIO_PATH);
|
||||
da->iface = qemu_dbus_display1_audio_skeleton_new();
|
||||
g_object_connect(da->iface,
|
||||
"swapped-signal::handle-register-in-listener",
|
||||
dbus_audio_register_in_listener, s,
|
||||
"swapped-signal::handle-register-out-listener",
|
||||
dbus_audio_register_out_listener, s,
|
||||
NULL);
|
||||
|
||||
g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(da->audio),
|
||||
G_DBUS_INTERFACE_SKELETON(da->iface));
|
||||
g_dbus_object_manager_server_export(da->server, da->audio);
|
||||
}
|
||||
|
||||
static struct audio_pcm_ops dbus_pcm_ops = {
|
||||
.init_out = dbus_init_out,
|
||||
.fini_out = dbus_fini_out,
|
||||
.write = audio_generic_write,
|
||||
.get_buffer_out = dbus_get_buffer_out,
|
||||
.put_buffer_out = dbus_put_buffer_out,
|
||||
.enable_out = dbus_enable_out,
|
||||
.volume_out = dbus_volume_out,
|
||||
|
||||
.init_in = dbus_init_in,
|
||||
.fini_in = dbus_fini_in,
|
||||
.read = dbus_read,
|
||||
.run_buffer_in = audio_generic_run_buffer_in,
|
||||
.enable_in = dbus_enable_in,
|
||||
.volume_in = dbus_volume_in,
|
||||
};
|
||||
|
||||
static struct audio_driver dbus_audio_driver = {
|
||||
.name = "dbus",
|
||||
.descr = "Timer based audio exposed with DBus interface",
|
||||
.init = dbus_audio_init,
|
||||
.fini = dbus_audio_fini,
|
||||
.set_dbus_server = dbus_audio_set_server,
|
||||
.pcm_ops = &dbus_pcm_ops,
|
||||
.can_be_default = 1,
|
||||
.max_voices_out = INT_MAX,
|
||||
.max_voices_in = INT_MAX,
|
||||
.voice_size_out = sizeof(DBusVoiceOut),
|
||||
.voice_size_in = sizeof(DBusVoiceIn)
|
||||
};
|
||||
|
||||
static void register_audio_dbus(void)
|
||||
{
|
||||
audio_driver_register(&dbus_audio_driver);
|
||||
}
|
||||
type_init(register_audio_dbus);
|
||||
|
||||
module_dep("ui-dbus")
|
@ -536,13 +536,12 @@ static void *dsound_get_buffer_in(HWVoiceIn *hw, size_t *size)
|
||||
DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
|
||||
LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
|
||||
HRESULT hr;
|
||||
DWORD cpos, rpos, act_size;
|
||||
DWORD rpos, act_size;
|
||||
size_t req_size;
|
||||
int err;
|
||||
void *ret;
|
||||
|
||||
hr = IDirectSoundCaptureBuffer_GetCurrentPosition(
|
||||
dscb, &cpos, ds->first_time ? &rpos : NULL);
|
||||
hr = IDirectSoundCaptureBuffer_GetCurrentPosition(dscb, NULL, &rpos);
|
||||
if (FAILED(hr)) {
|
||||
dsound_logerr(hr, "Could not get capture buffer position\n");
|
||||
*size = 0;
|
||||
@ -554,7 +553,7 @@ static void *dsound_get_buffer_in(HWVoiceIn *hw, size_t *size)
|
||||
ds->first_time = false;
|
||||
}
|
||||
|
||||
req_size = audio_ring_dist(cpos, hw->pos_emul, hw->size_emul);
|
||||
req_size = audio_ring_dist(rpos, hw->pos_emul, hw->size_emul);
|
||||
req_size = MIN(*size, MIN(req_size, hw->size_emul - hw->pos_emul));
|
||||
|
||||
if (req_size == 0) {
|
||||
|
@ -622,6 +622,7 @@ static void qjack_enable_in(HWVoiceIn *hw, bool enable)
|
||||
ji->c.enabled = enable;
|
||||
}
|
||||
|
||||
#if !defined(WIN32) && defined(CONFIG_PTHREAD_SETNAME_NP_W_TID)
|
||||
static int qjack_thread_creator(jack_native_thread_t *thread,
|
||||
const pthread_attr_t *attr, void *(*function)(void *), void *arg)
|
||||
{
|
||||
@ -635,6 +636,7 @@ static int qjack_thread_creator(jack_native_thread_t *thread,
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void *qjack_init(Audiodev *dev)
|
||||
{
|
||||
@ -687,7 +689,9 @@ static void register_audio_jack(void)
|
||||
{
|
||||
qemu_mutex_init(&qjack_shutdown_lock);
|
||||
audio_driver_register(&jack_driver);
|
||||
#if !defined(WIN32) && defined(CONFIG_PTHREAD_SETNAME_NP_W_TID)
|
||||
jack_set_thread_creator(qjack_thread_creator);
|
||||
#endif
|
||||
jack_set_error_function(qjack_error);
|
||||
jack_set_info_function(qjack_info);
|
||||
}
|
||||
|
@ -26,4 +26,10 @@ foreach m : [
|
||||
endif
|
||||
endforeach
|
||||
|
||||
if dbus_display
|
||||
module_ss = ss.source_set()
|
||||
module_ss.add(when: gio, if_true: files('dbusaudio.c'))
|
||||
audio_modules += {'dbus': module_ss}
|
||||
endif
|
||||
|
||||
modules += {'audio': audio_modules}
|
||||
|
@ -13,6 +13,11 @@ alsa_resume_out(void) "Resuming suspended output stream"
|
||||
# ossaudio.c
|
||||
oss_version(int version) "OSS version = 0x%x"
|
||||
|
||||
# dbusaudio.c
|
||||
dbus_audio_register(const char *s, const char *dir) "sender = %s, dir = %s"
|
||||
dbus_audio_put_buffer_out(size_t len) "len = %zu"
|
||||
dbus_audio_read(size_t len) "len = %zu"
|
||||
|
||||
# audio.c
|
||||
audio_timer_start(int interval) "interval %d ms"
|
||||
audio_timer_stop(void) ""
|
||||
|
52
backends/dbus-vmstate1.xml
Normal file
52
backends/dbus-vmstate1.xml
Normal file
@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
|
||||
<!--
|
||||
org.qemu.VMState1:
|
||||
|
||||
This interface must be implemented at the object path
|
||||
``/org/qemu/VMState1`` to support helper migration.
|
||||
-->
|
||||
<interface name="org.qemu.VMState1">
|
||||
|
||||
<!--
|
||||
Id:
|
||||
|
||||
A string that identifies the helper uniquely. (maximum 256 bytes
|
||||
including terminating NUL byte)
|
||||
|
||||
.. note::
|
||||
|
||||
The VMState helper ID namespace is its own namespace. In particular,
|
||||
it is not related to QEMU "id" used in -object/-device objects.
|
||||
-->
|
||||
<property name="Id" type="s" access="read"/>
|
||||
|
||||
<!--
|
||||
Load:
|
||||
@data: data to restore the state.
|
||||
|
||||
The method called on destination with the state to restore.
|
||||
|
||||
The helper may be initially started in a waiting state (with an
|
||||
``-incoming`` argument for example), and it may resume on success.
|
||||
|
||||
An error may be returned to the caller.
|
||||
-->
|
||||
<method name="Load">
|
||||
<arg type="ay" name="data" direction="in"/>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
Save:
|
||||
@data: state data to save for later resume.
|
||||
|
||||
The method called on the source to get the current state to be
|
||||
migrated. The helper should continue to run normally.
|
||||
|
||||
An error may be returned to the caller.
|
||||
-->
|
||||
<method name="Save">
|
||||
<arg type="ay" name="data" direction="out"/>
|
||||
</method>
|
||||
</interface>
|
||||
</node>
|
11
block.c
11
block.c
@ -103,6 +103,8 @@ static int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
|
||||
static void bdrv_reopen_commit(BDRVReopenState *reopen_state);
|
||||
static void bdrv_reopen_abort(BDRVReopenState *reopen_state);
|
||||
|
||||
static bool bdrv_backing_overridden(BlockDriverState *bs);
|
||||
|
||||
/* If non-zero, use only whitelisted block drivers */
|
||||
static int use_bdrv_whitelist;
|
||||
|
||||
@ -2483,7 +2485,6 @@ char *bdrv_perm_names(uint64_t perm)
|
||||
{ BLK_PERM_WRITE, "write" },
|
||||
{ BLK_PERM_WRITE_UNCHANGED, "write unchanged" },
|
||||
{ BLK_PERM_RESIZE, "resize" },
|
||||
{ BLK_PERM_GRAPH_MOD, "change children" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
@ -2599,8 +2600,7 @@ static void bdrv_default_perms_for_cow(BlockDriverState *bs, BdrvChild *c,
|
||||
shared = 0;
|
||||
}
|
||||
|
||||
shared |= BLK_PERM_CONSISTENT_READ | BLK_PERM_GRAPH_MOD |
|
||||
BLK_PERM_WRITE_UNCHANGED;
|
||||
shared |= BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED;
|
||||
|
||||
if (bs->open_flags & BDRV_O_INACTIVE) {
|
||||
shared |= BLK_PERM_WRITE | BLK_PERM_RESIZE;
|
||||
@ -2718,7 +2718,6 @@ uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm)
|
||||
[BLOCK_PERMISSION_WRITE] = BLK_PERM_WRITE,
|
||||
[BLOCK_PERMISSION_WRITE_UNCHANGED] = BLK_PERM_WRITE_UNCHANGED,
|
||||
[BLOCK_PERMISSION_RESIZE] = BLK_PERM_RESIZE,
|
||||
[BLOCK_PERMISSION_GRAPH_MOD] = BLK_PERM_GRAPH_MOD,
|
||||
};
|
||||
|
||||
QEMU_BUILD_BUG_ON(ARRAY_SIZE(permissions) != BLOCK_PERMISSION__MAX);
|
||||
@ -5544,8 +5543,6 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
|
||||
update_inherits_from = bdrv_inherits_from_recursive(base, explicit_top);
|
||||
|
||||
/* success - we can delete the intermediate states, and link top->base */
|
||||
/* TODO Check graph modification op blockers (BLK_PERM_GRAPH_MOD) once
|
||||
* we've figured out how they should work. */
|
||||
if (!backing_file_str) {
|
||||
bdrv_refresh_filename(base);
|
||||
backing_file_str = base->filename;
|
||||
@ -7475,7 +7472,7 @@ static bool append_strong_runtime_options(QDict *d, BlockDriverState *bs)
|
||||
/* Note: This function may return false positives; it may return true
|
||||
* even if opening the backing file specified by bs's image header
|
||||
* would result in exactly bs->backing. */
|
||||
bool bdrv_backing_overridden(BlockDriverState *bs)
|
||||
static bool bdrv_backing_overridden(BlockDriverState *bs)
|
||||
{
|
||||
if (bs->backing) {
|
||||
return strcmp(bs->auto_backing_file,
|
||||
|
@ -822,16 +822,22 @@ BlockBackend *blk_by_public(BlockBackendPublic *public)
|
||||
void blk_remove_bs(BlockBackend *blk)
|
||||
{
|
||||
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
|
||||
BlockDriverState *bs;
|
||||
BdrvChild *root;
|
||||
|
||||
notifier_list_notify(&blk->remove_bs_notifiers, blk);
|
||||
if (tgm->throttle_state) {
|
||||
bs = blk_bs(blk);
|
||||
BlockDriverState *bs = blk_bs(blk);
|
||||
|
||||
/*
|
||||
* Take a ref in case blk_bs() changes across bdrv_drained_begin(), for
|
||||
* example, if a temporary filter node is removed by a blockjob.
|
||||
*/
|
||||
bdrv_ref(bs);
|
||||
bdrv_drained_begin(bs);
|
||||
throttle_group_detach_aio_context(tgm);
|
||||
throttle_group_attach_aio_context(tgm, qemu_get_aio_context());
|
||||
bdrv_drained_end(bs);
|
||||
bdrv_unref(bs);
|
||||
}
|
||||
|
||||
blk_update_root_state(blk);
|
||||
@ -1705,6 +1711,7 @@ void blk_drain(BlockBackend *blk)
|
||||
BlockDriverState *bs = blk_bs(blk);
|
||||
|
||||
if (bs) {
|
||||
bdrv_ref(bs);
|
||||
bdrv_drained_begin(bs);
|
||||
}
|
||||
|
||||
@ -1714,6 +1721,7 @@ void blk_drain(BlockBackend *blk)
|
||||
|
||||
if (bs) {
|
||||
bdrv_drained_end(bs);
|
||||
bdrv_unref(bs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2044,10 +2052,13 @@ static int blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context,
|
||||
int ret;
|
||||
|
||||
if (bs) {
|
||||
bdrv_ref(bs);
|
||||
|
||||
if (update_root_node) {
|
||||
ret = bdrv_child_try_set_aio_context(bs, new_context, blk->root,
|
||||
errp);
|
||||
if (ret < 0) {
|
||||
bdrv_unref(bs);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@ -2057,6 +2068,8 @@ static int blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context,
|
||||
throttle_group_attach_aio_context(tgm, new_context);
|
||||
bdrv_drained_end(bs);
|
||||
}
|
||||
|
||||
bdrv_unref(bs);
|
||||
}
|
||||
|
||||
blk->ctx = new_context;
|
||||
@ -2326,11 +2339,13 @@ void blk_io_limits_disable(BlockBackend *blk)
|
||||
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
|
||||
assert(tgm->throttle_state);
|
||||
if (bs) {
|
||||
bdrv_ref(bs);
|
||||
bdrv_drained_begin(bs);
|
||||
}
|
||||
throttle_group_unregister_tgm(tgm);
|
||||
if (bs) {
|
||||
bdrv_drained_end(bs);
|
||||
bdrv_unref(bs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -370,7 +370,6 @@ void commit_start(const char *job_id, BlockDriverState *bs,
|
||||
s->base = blk_new(s->common.job.aio_context,
|
||||
base_perms,
|
||||
BLK_PERM_CONSISTENT_READ
|
||||
| BLK_PERM_GRAPH_MOD
|
||||
| BLK_PERM_WRITE_UNCHANGED);
|
||||
ret = blk_insert_bs(s->base, base, errp);
|
||||
if (ret < 0) {
|
||||
|
11
block/curl.c
11
block/curl.c
@ -125,7 +125,7 @@ static gboolean curl_drop_socket(void *key, void *value, void *opaque)
|
||||
BDRVCURLState *s = socket->s;
|
||||
|
||||
aio_set_fd_handler(s->aio_context, socket->fd, false,
|
||||
NULL, NULL, NULL, NULL);
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -173,19 +173,20 @@ static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
|
||||
switch (action) {
|
||||
case CURL_POLL_IN:
|
||||
aio_set_fd_handler(s->aio_context, fd, false,
|
||||
curl_multi_do, NULL, NULL, socket);
|
||||
curl_multi_do, NULL, NULL, NULL, socket);
|
||||
break;
|
||||
case CURL_POLL_OUT:
|
||||
aio_set_fd_handler(s->aio_context, fd, false,
|
||||
NULL, curl_multi_do, NULL, socket);
|
||||
NULL, curl_multi_do, NULL, NULL, socket);
|
||||
break;
|
||||
case CURL_POLL_INOUT:
|
||||
aio_set_fd_handler(s->aio_context, fd, false,
|
||||
curl_multi_do, curl_multi_do, NULL, socket);
|
||||
curl_multi_do, curl_multi_do,
|
||||
NULL, NULL, socket);
|
||||
break;
|
||||
case CURL_POLL_REMOVE:
|
||||
aio_set_fd_handler(s->aio_context, fd, false,
|
||||
NULL, NULL, NULL, NULL);
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -223,7 +223,7 @@ static int setup_fuse_export(FuseExport *exp, const char *mountpoint,
|
||||
|
||||
aio_set_fd_handler(exp->common.ctx,
|
||||
fuse_session_fd(exp->fuse_session), true,
|
||||
read_from_fuse_export, NULL, NULL, exp);
|
||||
read_from_fuse_export, NULL, NULL, NULL, exp);
|
||||
exp->fd_handler_set_up = true;
|
||||
|
||||
return 0;
|
||||
@ -267,7 +267,7 @@ static void fuse_export_shutdown(BlockExport *blk_exp)
|
||||
if (exp->fd_handler_set_up) {
|
||||
aio_set_fd_handler(exp->common.ctx,
|
||||
fuse_session_fd(exp->fuse_session), true,
|
||||
NULL, NULL, NULL, NULL);
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
exp->fd_handler_set_up = false;
|
||||
}
|
||||
}
|
||||
|
@ -106,10 +106,6 @@
|
||||
#include <sys/diskslice.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_XFS
|
||||
#include <xfs/xfs.h>
|
||||
#endif
|
||||
|
||||
/* OS X does not have O_DSYNC */
|
||||
#ifndef O_DSYNC
|
||||
#ifdef O_SYNC
|
||||
@ -156,9 +152,6 @@ typedef struct BDRVRawState {
|
||||
int perm_change_flags;
|
||||
BDRVReopenState *reopen_state;
|
||||
|
||||
#ifdef CONFIG_XFS
|
||||
bool is_xfs:1;
|
||||
#endif
|
||||
bool has_discard:1;
|
||||
bool has_write_zeroes:1;
|
||||
bool discard_zeroes:1;
|
||||
@ -409,15 +402,23 @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp)
|
||||
if (probe_logical_blocksize(fd, &bs->bl.request_alignment) < 0) {
|
||||
bs->bl.request_alignment = 0;
|
||||
}
|
||||
#ifdef CONFIG_XFS
|
||||
if (s->is_xfs) {
|
||||
struct dioattr da;
|
||||
if (xfsctl(NULL, fd, XFS_IOC_DIOINFO, &da) >= 0) {
|
||||
|
||||
#ifdef __linux__
|
||||
/*
|
||||
* The XFS ioctl definitions are shipped in extra packages that might
|
||||
* not always be available. Since we just need the XFS_IOC_DIOINFO ioctl
|
||||
* here, we simply use our own definition instead:
|
||||
*/
|
||||
struct xfs_dioattr {
|
||||
uint32_t d_mem;
|
||||
uint32_t d_miniosz;
|
||||
uint32_t d_maxiosz;
|
||||
} da;
|
||||
if (ioctl(fd, _IOR('X', 30, struct xfs_dioattr), &da) >= 0) {
|
||||
bs->bl.request_alignment = da.d_miniosz;
|
||||
/* The kernel returns wrong information for d_mem */
|
||||
/* s->buf_align = da.d_mem; */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -798,12 +799,6 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
#endif
|
||||
s->needs_alignment = raw_needs_alignment(bs);
|
||||
|
||||
#ifdef CONFIG_XFS
|
||||
if (platform_test_xfs_fd(s->fd)) {
|
||||
s->is_xfs = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK;
|
||||
if (S_ISREG(st.st_mode)) {
|
||||
/* When extending regular files, we get zeros from the OS */
|
||||
|
@ -292,12 +292,14 @@ static bool qemu_luring_poll_cb(void *opaque)
|
||||
{
|
||||
LuringState *s = opaque;
|
||||
|
||||
if (io_uring_cq_ready(&s->ring)) {
|
||||
luring_process_completions_and_submit(s);
|
||||
return true;
|
||||
return io_uring_cq_ready(&s->ring);
|
||||
}
|
||||
|
||||
return false;
|
||||
static void qemu_luring_poll_ready(void *opaque)
|
||||
{
|
||||
LuringState *s = opaque;
|
||||
|
||||
luring_process_completions_and_submit(s);
|
||||
}
|
||||
|
||||
static void ioq_init(LuringQueue *io_q)
|
||||
@ -402,8 +404,8 @@ int coroutine_fn luring_co_submit(BlockDriverState *bs, LuringState *s, int fd,
|
||||
|
||||
void luring_detach_aio_context(LuringState *s, AioContext *old_context)
|
||||
{
|
||||
aio_set_fd_handler(old_context, s->ring.ring_fd, false, NULL, NULL, NULL,
|
||||
s);
|
||||
aio_set_fd_handler(old_context, s->ring.ring_fd, false,
|
||||
NULL, NULL, NULL, NULL, s);
|
||||
qemu_bh_delete(s->completion_bh);
|
||||
s->aio_context = NULL;
|
||||
}
|
||||
@ -413,7 +415,8 @@ void luring_attach_aio_context(LuringState *s, AioContext *new_context)
|
||||
s->aio_context = new_context;
|
||||
s->completion_bh = aio_bh_new(new_context, qemu_luring_completion_bh, s);
|
||||
aio_set_fd_handler(s->aio_context, s->ring.ring_fd, false,
|
||||
qemu_luring_completion_cb, NULL, qemu_luring_poll_cb, s);
|
||||
qemu_luring_completion_cb, NULL,
|
||||
qemu_luring_poll_cb, qemu_luring_poll_ready, s);
|
||||
}
|
||||
|
||||
LuringState *luring_init(Error **errp)
|
||||
|
@ -363,7 +363,7 @@ iscsi_set_events(IscsiLun *iscsilun)
|
||||
false,
|
||||
(ev & POLLIN) ? iscsi_process_read : NULL,
|
||||
(ev & POLLOUT) ? iscsi_process_write : NULL,
|
||||
NULL,
|
||||
NULL, NULL,
|
||||
iscsilun);
|
||||
iscsilun->events = ev;
|
||||
}
|
||||
@ -1534,7 +1534,7 @@ static void iscsi_detach_aio_context(BlockDriverState *bs)
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
|
||||
aio_set_fd_handler(iscsilun->aio_context, iscsi_get_fd(iscsilun->iscsi),
|
||||
false, NULL, NULL, NULL, NULL);
|
||||
false, NULL, NULL, NULL, NULL, NULL);
|
||||
iscsilun->events = 0;
|
||||
|
||||
if (iscsilun->nop_timer) {
|
||||
|
@ -263,12 +263,15 @@ static bool qemu_laio_poll_cb(void *opaque)
|
||||
LinuxAioState *s = container_of(e, LinuxAioState, e);
|
||||
struct io_event *events;
|
||||
|
||||
if (!io_getevents_peek(s->ctx, &events)) {
|
||||
return false;
|
||||
return io_getevents_peek(s->ctx, &events);
|
||||
}
|
||||
|
||||
static void qemu_laio_poll_ready(EventNotifier *opaque)
|
||||
{
|
||||
EventNotifier *e = opaque;
|
||||
LinuxAioState *s = container_of(e, LinuxAioState, e);
|
||||
|
||||
qemu_laio_process_completions_and_submit(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ioq_init(LaioQueue *io_q)
|
||||
@ -427,7 +430,7 @@ int coroutine_fn laio_co_submit(BlockDriverState *bs, LinuxAioState *s, int fd,
|
||||
|
||||
void laio_detach_aio_context(LinuxAioState *s, AioContext *old_context)
|
||||
{
|
||||
aio_set_event_notifier(old_context, &s->e, false, NULL, NULL);
|
||||
aio_set_event_notifier(old_context, &s->e, false, NULL, NULL, NULL);
|
||||
qemu_bh_delete(s->completion_bh);
|
||||
s->aio_context = NULL;
|
||||
}
|
||||
@ -438,7 +441,8 @@ void laio_attach_aio_context(LinuxAioState *s, AioContext *new_context)
|
||||
s->completion_bh = aio_bh_new(new_context, qemu_laio_completion_bh, s);
|
||||
aio_set_event_notifier(new_context, &s->e, false,
|
||||
qemu_laio_completion_cb,
|
||||
qemu_laio_poll_cb);
|
||||
qemu_laio_poll_cb,
|
||||
qemu_laio_poll_ready);
|
||||
}
|
||||
|
||||
LinuxAioState *laio_init(Error **errp)
|
||||
|
@ -771,13 +771,6 @@ static int mirror_exit_common(Job *job)
|
||||
block_job_remove_all_bdrv(bjob);
|
||||
bdrv_replace_node(mirror_top_bs, mirror_top_bs->backing->bs, &error_abort);
|
||||
|
||||
/* We just changed the BDS the job BB refers to (with either or both of the
|
||||
* bdrv_replace_node() calls), so switch the BB back so the cleanup does
|
||||
* the right thing. We don't need any permissions any more now. */
|
||||
blk_remove_bs(bjob->blk);
|
||||
blk_set_perm(bjob->blk, 0, BLK_PERM_ALL, &error_abort);
|
||||
blk_insert_bs(bjob->blk, mirror_top_bs, &error_abort);
|
||||
|
||||
bs_opaque->job = NULL;
|
||||
|
||||
bdrv_drained_end(src);
|
||||
@ -1146,10 +1139,7 @@ static void mirror_complete(Job *job, Error **errp)
|
||||
replace_aio_context = bdrv_get_aio_context(s->to_replace);
|
||||
aio_context_acquire(replace_aio_context);
|
||||
|
||||
/* TODO Translate this into permission system. Current definition of
|
||||
* GRAPH_MOD would require to request it for the parents; they might
|
||||
* not even be BlockDriverStates, however, so a BdrvChild can't address
|
||||
* them. May need redefinition of GRAPH_MOD. */
|
||||
/* TODO Translate this into child freeze system. */
|
||||
error_setg(&s->replace_blocker,
|
||||
"block device is in use by block-job-complete");
|
||||
bdrv_op_block_all(s->to_replace, s->replace_blocker);
|
||||
@ -1673,7 +1663,7 @@ static BlockJob *mirror_start_job(
|
||||
s = block_job_create(job_id, driver, NULL, mirror_top_bs,
|
||||
BLK_PERM_CONSISTENT_READ,
|
||||
BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
|
||||
BLK_PERM_WRITE | BLK_PERM_GRAPH_MOD, speed,
|
||||
BLK_PERM_WRITE, speed,
|
||||
creation_flags, cb, opaque, errp);
|
||||
if (!s) {
|
||||
goto fail;
|
||||
@ -1717,9 +1707,7 @@ static BlockJob *mirror_start_job(
|
||||
target_perms |= BLK_PERM_RESIZE;
|
||||
}
|
||||
|
||||
target_shared_perms |= BLK_PERM_CONSISTENT_READ
|
||||
| BLK_PERM_WRITE
|
||||
| BLK_PERM_GRAPH_MOD;
|
||||
target_shared_perms |= BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE;
|
||||
} else if (bdrv_chain_contains(bs, bdrv_skip_filters(target))) {
|
||||
/*
|
||||
* We may want to allow this in the future, but it would
|
||||
@ -1730,10 +1718,6 @@ static BlockJob *mirror_start_job(
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (backing_mode != MIRROR_LEAVE_BACKING_CHAIN) {
|
||||
target_perms |= BLK_PERM_GRAPH_MOD;
|
||||
}
|
||||
|
||||
s->target = blk_new(s->common.job.aio_context,
|
||||
target_perms, target_shared_perms);
|
||||
ret = blk_insert_bs(s->target, target, errp);
|
||||
|
@ -101,7 +101,7 @@ void hmp_drive_add(Monitor *mon, const QDict *qdict)
|
||||
return;
|
||||
}
|
||||
|
||||
opts = drive_def(optstr);
|
||||
opts = qemu_opts_parse_noisily(qemu_find_opts("drive"), optstr, false);
|
||||
if (!opts)
|
||||
return;
|
||||
|
||||
|
45
block/nbd.c
45
block/nbd.c
@ -80,6 +80,7 @@ typedef struct BDRVNBDState {
|
||||
NBDClientState state;
|
||||
|
||||
QEMUTimer *reconnect_delay_timer;
|
||||
QEMUTimer *open_timer;
|
||||
|
||||
NBDClientRequest requests[MAX_NBD_REQUESTS];
|
||||
NBDReply reply;
|
||||
@ -87,6 +88,7 @@ typedef struct BDRVNBDState {
|
||||
|
||||
/* Connection parameters */
|
||||
uint32_t reconnect_delay;
|
||||
uint32_t open_timeout;
|
||||
SocketAddress *saddr;
|
||||
char *export, *tlscredsid;
|
||||
QCryptoTLSCreds *tlscreds;
|
||||
@ -218,6 +220,32 @@ static void nbd_teardown_connection(BlockDriverState *bs)
|
||||
s->state = NBD_CLIENT_QUIT;
|
||||
}
|
||||
|
||||
static void open_timer_del(BDRVNBDState *s)
|
||||
{
|
||||
if (s->open_timer) {
|
||||
timer_free(s->open_timer);
|
||||
s->open_timer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void open_timer_cb(void *opaque)
|
||||
{
|
||||
BDRVNBDState *s = opaque;
|
||||
|
||||
nbd_co_establish_connection_cancel(s->conn);
|
||||
open_timer_del(s);
|
||||
}
|
||||
|
||||
static void open_timer_init(BDRVNBDState *s, uint64_t expire_time_ns)
|
||||
{
|
||||
assert(!s->open_timer);
|
||||
s->open_timer = aio_timer_new(bdrv_get_aio_context(s->bs),
|
||||
QEMU_CLOCK_REALTIME,
|
||||
SCALE_NS,
|
||||
open_timer_cb, s);
|
||||
timer_mod(s->open_timer, expire_time_ns);
|
||||
}
|
||||
|
||||
static bool nbd_client_connecting(BDRVNBDState *s)
|
||||
{
|
||||
NBDClientState state = qatomic_load_acquire(&s->state);
|
||||
@ -1742,6 +1770,15 @@ static QemuOptsList nbd_runtime_opts = {
|
||||
"future requests before a successful reconnect will "
|
||||
"immediately fail. Default 0",
|
||||
},
|
||||
{
|
||||
.name = "open-timeout",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "In seconds. If zero, the nbd driver tries the connection "
|
||||
"only once, and fails to open if the connection fails. "
|
||||
"If non-zero, the nbd driver will repeat connection "
|
||||
"attempts until successful or until @open-timeout seconds "
|
||||
"have elapsed. Default 0",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
@ -1797,6 +1834,7 @@ static int nbd_process_options(BlockDriverState *bs, QDict *options,
|
||||
}
|
||||
|
||||
s->reconnect_delay = qemu_opt_get_number(opts, "reconnect-delay", 0);
|
||||
s->open_timeout = qemu_opt_get_number(opts, "open-timeout", 0);
|
||||
|
||||
ret = 0;
|
||||
|
||||
@ -1828,7 +1866,12 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
s->conn = nbd_client_connection_new(s->saddr, true, s->export,
|
||||
s->x_dirty_bitmap, s->tlscreds);
|
||||
|
||||
/* TODO: Configurable retry-until-timeout behaviour. */
|
||||
if (s->open_timeout) {
|
||||
nbd_client_connection_enable_retry(s->conn);
|
||||
open_timer_init(s, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) +
|
||||
s->open_timeout * NANOSECONDS_PER_SECOND);
|
||||
}
|
||||
|
||||
s->state = NBD_CLIENT_CONNECTING_WAIT;
|
||||
ret = nbd_do_establish_connection(bs, errp);
|
||||
if (ret < 0) {
|
||||
|
@ -197,7 +197,7 @@ static void nfs_set_events(NFSClient *client)
|
||||
false,
|
||||
(ev & POLLIN) ? nfs_process_read : NULL,
|
||||
(ev & POLLOUT) ? nfs_process_write : NULL,
|
||||
NULL, client);
|
||||
NULL, NULL, client);
|
||||
|
||||
}
|
||||
client->events = ev;
|
||||
@ -372,7 +372,7 @@ static void nfs_detach_aio_context(BlockDriverState *bs)
|
||||
NFSClient *client = bs->opaque;
|
||||
|
||||
aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context),
|
||||
false, NULL, NULL, NULL, NULL);
|
||||
false, NULL, NULL, NULL, NULL, NULL);
|
||||
client->events = 0;
|
||||
}
|
||||
|
||||
@ -390,7 +390,7 @@ static void nfs_client_close(NFSClient *client)
|
||||
if (client->context) {
|
||||
qemu_mutex_lock(&client->mutex);
|
||||
aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context),
|
||||
false, NULL, NULL, NULL, NULL);
|
||||
false, NULL, NULL, NULL, NULL, NULL);
|
||||
qemu_mutex_unlock(&client->mutex);
|
||||
if (client->fh) {
|
||||
nfs_close(client->context, client->fh);
|
||||
|
51
block/nvme.c
51
block/nvme.c
@ -605,10 +605,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool nvme_poll_queue(NVMeQueuePair *q)
|
||||
static void nvme_poll_queue(NVMeQueuePair *q)
|
||||
{
|
||||
bool progress = false;
|
||||
|
||||
const size_t cqe_offset = q->cq.head * NVME_CQ_ENTRY_BYTES;
|
||||
NvmeCqe *cqe = (NvmeCqe *)&q->cq.queue[cqe_offset];
|
||||
|
||||
@ -619,31 +617,24 @@ static bool nvme_poll_queue(NVMeQueuePair *q)
|
||||
* cannot race with itself.
|
||||
*/
|
||||
if ((le16_to_cpu(cqe->status) & 0x1) == q->cq_phase) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_mutex_lock(&q->lock);
|
||||
while (nvme_process_completion(q)) {
|
||||
/* Keep polling */
|
||||
progress = true;
|
||||
}
|
||||
qemu_mutex_unlock(&q->lock);
|
||||
|
||||
return progress;
|
||||
}
|
||||
|
||||
static bool nvme_poll_queues(BDRVNVMeState *s)
|
||||
static void nvme_poll_queues(BDRVNVMeState *s)
|
||||
{
|
||||
bool progress = false;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s->queue_count; i++) {
|
||||
if (nvme_poll_queue(s->queues[i])) {
|
||||
progress = true;
|
||||
nvme_poll_queue(s->queues[i]);
|
||||
}
|
||||
}
|
||||
return progress;
|
||||
}
|
||||
|
||||
static void nvme_handle_event(EventNotifier *n)
|
||||
{
|
||||
@ -703,8 +694,30 @@ static bool nvme_poll_cb(void *opaque)
|
||||
EventNotifier *e = opaque;
|
||||
BDRVNVMeState *s = container_of(e, BDRVNVMeState,
|
||||
irq_notifier[MSIX_SHARED_IRQ_IDX]);
|
||||
int i;
|
||||
|
||||
return nvme_poll_queues(s);
|
||||
for (i = 0; i < s->queue_count; i++) {
|
||||
NVMeQueuePair *q = s->queues[i];
|
||||
const size_t cqe_offset = q->cq.head * NVME_CQ_ENTRY_BYTES;
|
||||
NvmeCqe *cqe = (NvmeCqe *)&q->cq.queue[cqe_offset];
|
||||
|
||||
/*
|
||||
* q->lock isn't needed because nvme_process_completion() only runs in
|
||||
* the event loop thread and cannot race with itself.
|
||||
*/
|
||||
if ((le16_to_cpu(cqe->status) & 0x1) != q->cq_phase) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void nvme_poll_ready(EventNotifier *e)
|
||||
{
|
||||
BDRVNVMeState *s = container_of(e, BDRVNVMeState,
|
||||
irq_notifier[MSIX_SHARED_IRQ_IDX]);
|
||||
|
||||
nvme_poll_queues(s);
|
||||
}
|
||||
|
||||
static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
|
||||
@ -839,7 +852,8 @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
|
||||
}
|
||||
aio_set_event_notifier(bdrv_get_aio_context(bs),
|
||||
&s->irq_notifier[MSIX_SHARED_IRQ_IDX],
|
||||
false, nvme_handle_event, nvme_poll_cb);
|
||||
false, nvme_handle_event, nvme_poll_cb,
|
||||
nvme_poll_ready);
|
||||
|
||||
if (!nvme_identify(bs, namespace, errp)) {
|
||||
ret = -EIO;
|
||||
@ -924,7 +938,7 @@ static void nvme_close(BlockDriverState *bs)
|
||||
g_free(s->queues);
|
||||
aio_set_event_notifier(bdrv_get_aio_context(bs),
|
||||
&s->irq_notifier[MSIX_SHARED_IRQ_IDX],
|
||||
false, NULL, NULL);
|
||||
false, NULL, NULL, NULL);
|
||||
event_notifier_cleanup(&s->irq_notifier[MSIX_SHARED_IRQ_IDX]);
|
||||
qemu_vfio_pci_unmap_bar(s->vfio, 0, s->bar0_wo_map,
|
||||
0, sizeof(NvmeBar) + NVME_DOORBELL_SIZE);
|
||||
@ -1520,7 +1534,7 @@ static void nvme_detach_aio_context(BlockDriverState *bs)
|
||||
|
||||
aio_set_event_notifier(bdrv_get_aio_context(bs),
|
||||
&s->irq_notifier[MSIX_SHARED_IRQ_IDX],
|
||||
false, NULL, NULL);
|
||||
false, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static void nvme_attach_aio_context(BlockDriverState *bs,
|
||||
@ -1530,7 +1544,8 @@ static void nvme_attach_aio_context(BlockDriverState *bs,
|
||||
|
||||
s->aio_context = new_context;
|
||||
aio_set_event_notifier(new_context, &s->irq_notifier[MSIX_SHARED_IRQ_IDX],
|
||||
false, nvme_handle_event, nvme_poll_cb);
|
||||
false, nvme_handle_event, nvme_poll_cb,
|
||||
nvme_poll_ready);
|
||||
|
||||
for (unsigned i = 0; i < s->queue_count; i++) {
|
||||
NVMeQueuePair *q = s->queues[i];
|
||||
|
@ -990,7 +990,7 @@ static void restart_coroutine(void *opaque)
|
||||
AioContext *ctx = bdrv_get_aio_context(bs);
|
||||
|
||||
trace_ssh_restart_coroutine(restart->co);
|
||||
aio_set_fd_handler(ctx, s->sock, false, NULL, NULL, NULL, NULL);
|
||||
aio_set_fd_handler(ctx, s->sock, false, NULL, NULL, NULL, NULL, NULL);
|
||||
|
||||
aio_co_wake(restart->co);
|
||||
}
|
||||
@ -1020,7 +1020,7 @@ static coroutine_fn void co_yield(BDRVSSHState *s, BlockDriverState *bs)
|
||||
trace_ssh_co_yield(s->sock, rd_handler, wr_handler);
|
||||
|
||||
aio_set_fd_handler(bdrv_get_aio_context(bs), s->sock,
|
||||
false, rd_handler, wr_handler, NULL, &restart);
|
||||
false, rd_handler, wr_handler, NULL, NULL, &restart);
|
||||
qemu_coroutine_yield();
|
||||
trace_ssh_co_yield_back(s->sock);
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ enum {
|
||||
|
||||
typedef struct StreamBlockJob {
|
||||
BlockJob common;
|
||||
BlockBackend *blk;
|
||||
BlockDriverState *base_overlay; /* COW overlay (stream from this) */
|
||||
BlockDriverState *above_base; /* Node directly above the base */
|
||||
BlockDriverState *cor_filter_bs;
|
||||
@ -88,17 +89,18 @@ static int stream_prepare(Job *job)
|
||||
static void stream_clean(Job *job)
|
||||
{
|
||||
StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
|
||||
BlockJob *bjob = &s->common;
|
||||
|
||||
if (s->cor_filter_bs) {
|
||||
bdrv_cor_filter_drop(s->cor_filter_bs);
|
||||
s->cor_filter_bs = NULL;
|
||||
}
|
||||
|
||||
blk_unref(s->blk);
|
||||
s->blk = NULL;
|
||||
|
||||
/* Reopen the image back in read-only mode if necessary */
|
||||
if (s->bs_read_only) {
|
||||
/* Give up write permissions before making it read-only */
|
||||
blk_set_perm(bjob->blk, 0, BLK_PERM_ALL, &error_abort);
|
||||
bdrv_reopen_set_read_only(s->target_bs, true, NULL);
|
||||
}
|
||||
|
||||
@ -108,7 +110,6 @@ static void stream_clean(Job *job)
|
||||
static int coroutine_fn stream_run(Job *job, Error **errp)
|
||||
{
|
||||
StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
|
||||
BlockBackend *blk = s->common.blk;
|
||||
BlockDriverState *unfiltered_bs = bdrv_skip_filters(s->target_bs);
|
||||
int64_t len;
|
||||
int64_t offset = 0;
|
||||
@ -159,7 +160,7 @@ static int coroutine_fn stream_run(Job *job, Error **errp)
|
||||
}
|
||||
trace_stream_one_iteration(s, offset, n, ret);
|
||||
if (copy) {
|
||||
ret = stream_populate(blk, offset, n);
|
||||
ret = stream_populate(s->blk, offset, n);
|
||||
}
|
||||
if (ret < 0) {
|
||||
BlockErrorAction action =
|
||||
@ -294,13 +295,24 @@ void stream_start(const char *job_id, BlockDriverState *bs,
|
||||
}
|
||||
|
||||
s = block_job_create(job_id, &stream_job_driver, NULL, cor_filter_bs,
|
||||
BLK_PERM_CONSISTENT_READ,
|
||||
basic_flags | BLK_PERM_WRITE,
|
||||
0, BLK_PERM_ALL,
|
||||
speed, creation_flags, NULL, NULL, errp);
|
||||
if (!s) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
s->blk = blk_new_with_bs(cor_filter_bs, BLK_PERM_CONSISTENT_READ,
|
||||
basic_flags | BLK_PERM_WRITE, errp);
|
||||
if (!s->blk) {
|
||||
goto fail;
|
||||
}
|
||||
/*
|
||||
* Disable request queuing in the BlockBackend to avoid deadlocks on drain:
|
||||
* The job reports that it's busy until it reaches a pause point.
|
||||
*/
|
||||
blk_set_disable_request_queuing(s->blk, true);
|
||||
blk_set_allow_aio_context_change(s->blk, true);
|
||||
|
||||
/*
|
||||
* Prevent concurrent jobs trying to modify the graph structure here, we
|
||||
* already have our own plans. Also don't allow resize as the image size is
|
||||
|
@ -882,7 +882,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
|
||||
static inline int32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
|
||||
{
|
||||
return (sector_num - s->offset_to_root_dir) / s->sectors_per_cluster;
|
||||
}
|
||||
@ -1230,6 +1230,7 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
dirname, cyls, heads, secs));
|
||||
|
||||
s->sector_count = cyls * heads * secs - s->offset_to_bootsector;
|
||||
bs->total_sectors = cyls * heads * secs;
|
||||
|
||||
if (qemu_opt_get_bool(opts, "rw", false)) {
|
||||
if (!bdrv_is_read_only(bs)) {
|
||||
@ -1250,8 +1251,6 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
}
|
||||
|
||||
bs->total_sectors = cyls * heads * secs;
|
||||
|
||||
if (init_directories(s, dirname, heads, secs, errp)) {
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
@ -2982,6 +2981,7 @@ static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
|
||||
{
|
||||
BDRVVVFATState *s = bs->opaque;
|
||||
int i, ret;
|
||||
int first_cluster, last_cluster;
|
||||
|
||||
DLOG(checkpoint());
|
||||
|
||||
@ -3000,9 +3000,20 @@ DLOG(checkpoint());
|
||||
if (sector_num < s->offset_to_fat)
|
||||
return -1;
|
||||
|
||||
for (i = sector2cluster(s, sector_num);
|
||||
i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
|
||||
mapping_t* mapping = find_mapping_for_cluster(s, i);
|
||||
/*
|
||||
* Values will be negative for writes to the FAT, which is located before
|
||||
* the root directory.
|
||||
*/
|
||||
first_cluster = sector2cluster(s, sector_num);
|
||||
last_cluster = sector2cluster(s, sector_num + nb_sectors - 1);
|
||||
|
||||
for (i = first_cluster; i <= last_cluster;) {
|
||||
mapping_t *mapping = NULL;
|
||||
|
||||
if (i >= 0) {
|
||||
mapping = find_mapping_for_cluster(s, i);
|
||||
}
|
||||
|
||||
if (mapping) {
|
||||
if (mapping->read_only) {
|
||||
fprintf(stderr, "Tried to write to write-protected file %s\n",
|
||||
@ -3042,9 +3053,10 @@ DLOG(checkpoint());
|
||||
}
|
||||
}
|
||||
i = mapping->end;
|
||||
} else
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Use qcow backend. Commit later.
|
||||
@ -3057,10 +3069,11 @@ DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sec
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = sector2cluster(s, sector_num);
|
||||
i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
|
||||
if (i >= 0)
|
||||
for (i = first_cluster; i <= last_cluster; i++) {
|
||||
if (i >= 0) {
|
||||
s->used_clusters[i] |= USED_ALLOCATED;
|
||||
}
|
||||
}
|
||||
|
||||
DLOG(checkpoint());
|
||||
/* TODO: add timeout */
|
||||
@ -3147,8 +3160,8 @@ static int enable_write_target(BlockDriverState *bs, Error **errp)
|
||||
}
|
||||
|
||||
opts = qemu_opts_create(bdrv_qcow->create_opts, NULL, 0, &error_abort);
|
||||
qemu_opt_set_number(opts, BLOCK_OPT_SIZE, s->sector_count * 512,
|
||||
&error_abort);
|
||||
qemu_opt_set_number(opts, BLOCK_OPT_SIZE,
|
||||
bs->total_sectors * BDRV_SECTOR_SIZE, &error_abort);
|
||||
qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, "fat:", &error_abort);
|
||||
|
||||
ret = bdrv_create(bdrv_qcow, s->qcow_filename, opts, errp);
|
||||
|
@ -172,7 +172,7 @@ int win32_aio_attach(QEMUWin32AIOState *aio, HANDLE hfile)
|
||||
void win32_aio_detach_aio_context(QEMUWin32AIOState *aio,
|
||||
AioContext *old_context)
|
||||
{
|
||||
aio_set_event_notifier(old_context, &aio->e, false, NULL, NULL);
|
||||
aio_set_event_notifier(old_context, &aio->e, false, NULL, NULL, NULL);
|
||||
aio->aio_ctx = NULL;
|
||||
}
|
||||
|
||||
@ -181,7 +181,7 @@ void win32_aio_attach_aio_context(QEMUWin32AIOState *aio,
|
||||
{
|
||||
aio->aio_ctx = new_context;
|
||||
aio_set_event_notifier(new_context, &aio->e, false,
|
||||
win32_aio_completion_cb, NULL);
|
||||
win32_aio_completion_cb, NULL, NULL);
|
||||
}
|
||||
|
||||
QEMUWin32AIOState *win32_aio_init(void)
|
||||
|
30
blockdev.c
30
blockdev.c
@ -168,23 +168,6 @@ void blockdev_auto_del(BlockBackend *blk)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current mapping of how many units per bus
|
||||
* a particular interface can support.
|
||||
*
|
||||
* A positive integer indicates n units per bus.
|
||||
* 0 implies the mapping has not been established.
|
||||
* -1 indicates an invalid BlockInterfaceType was given.
|
||||
*/
|
||||
int drive_get_max_devs(BlockInterfaceType type)
|
||||
{
|
||||
if (type >= IF_IDE && type < IF_COUNT) {
|
||||
return if_max_devs[type];
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int drive_index_to_bus_id(BlockInterfaceType type, int index)
|
||||
{
|
||||
int max_devs = if_max_devs[type];
|
||||
@ -197,17 +180,12 @@ static int drive_index_to_unit_id(BlockInterfaceType type, int index)
|
||||
return max_devs ? index % max_devs : index;
|
||||
}
|
||||
|
||||
QemuOpts *drive_def(const char *optstr)
|
||||
{
|
||||
return qemu_opts_parse_noisily(qemu_find_opts("drive"), optstr, false);
|
||||
}
|
||||
|
||||
QemuOpts *drive_add(BlockInterfaceType type, int index, const char *file,
|
||||
const char *optstr)
|
||||
{
|
||||
QemuOpts *opts;
|
||||
|
||||
opts = drive_def(optstr);
|
||||
opts = qemu_opts_parse_noisily(qemu_find_opts("drive"), optstr, false);
|
||||
if (!opts) {
|
||||
return NULL;
|
||||
}
|
||||
@ -3315,7 +3293,7 @@ static BlockJob *find_block_job(const char *id, AioContext **aio_context,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*aio_context = blk_get_aio_context(job->blk);
|
||||
*aio_context = block_job_get_aio_context(job);
|
||||
aio_context_acquire(*aio_context);
|
||||
|
||||
return job;
|
||||
@ -3420,7 +3398,7 @@ void qmp_block_job_finalize(const char *id, Error **errp)
|
||||
* automatically acquires the new one), so make sure we release the correct
|
||||
* one.
|
||||
*/
|
||||
aio_context = blk_get_aio_context(job->blk);
|
||||
aio_context = block_job_get_aio_context(job);
|
||||
job_unref(&job->job);
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
@ -3711,7 +3689,7 @@ BlockJobInfoList *qmp_query_block_jobs(Error **errp)
|
||||
if (block_job_is_internal(job)) {
|
||||
continue;
|
||||
}
|
||||
aio_context = blk_get_aio_context(job->blk);
|
||||
aio_context = block_job_get_aio_context(job);
|
||||
aio_context_acquire(aio_context);
|
||||
value = block_job_query(job, errp);
|
||||
aio_context_release(aio_context);
|
||||
|
36
blockjob.c
36
blockjob.c
@ -86,7 +86,6 @@ void block_job_free(Job *job)
|
||||
BlockJob *bjob = container_of(job, BlockJob, job);
|
||||
|
||||
block_job_remove_all_bdrv(bjob);
|
||||
blk_unref(bjob->blk);
|
||||
ratelimit_destroy(&bjob->limit);
|
||||
error_free(bjob->blocker);
|
||||
}
|
||||
@ -433,22 +432,16 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
|
||||
uint64_t shared_perm, int64_t speed, int flags,
|
||||
BlockCompletionFunc *cb, void *opaque, Error **errp)
|
||||
{
|
||||
BlockBackend *blk;
|
||||
BlockJob *job;
|
||||
int ret;
|
||||
|
||||
if (job_id == NULL && !(flags & JOB_INTERNAL)) {
|
||||
job_id = bdrv_get_device_name(bs);
|
||||
}
|
||||
|
||||
blk = blk_new_with_bs(bs, perm, shared_perm, errp);
|
||||
if (!blk) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
job = job_create(job_id, &driver->job_driver, txn, blk_get_aio_context(blk),
|
||||
job = job_create(job_id, &driver->job_driver, txn, bdrv_get_aio_context(bs),
|
||||
flags, cb, opaque, errp);
|
||||
if (job == NULL) {
|
||||
blk_unref(blk);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -458,8 +451,6 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
|
||||
|
||||
ratelimit_init(&job->limit);
|
||||
|
||||
job->blk = blk;
|
||||
|
||||
job->finalize_cancelled_notifier.notify = block_job_event_cancelled;
|
||||
job->finalize_completed_notifier.notify = block_job_event_completed;
|
||||
job->pending_notifier.notify = block_job_event_pending;
|
||||
@ -476,21 +467,23 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
|
||||
|
||||
error_setg(&job->blocker, "block device is in use by block job: %s",
|
||||
job_type_str(&job->job));
|
||||
block_job_add_bdrv(job, "main node", bs, 0, BLK_PERM_ALL, &error_abort);
|
||||
|
||||
ret = block_job_add_bdrv(job, "main node", bs, perm, shared_perm, errp);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker);
|
||||
|
||||
/* Disable request queuing in the BlockBackend to avoid deadlocks on drain:
|
||||
* The job reports that it's busy until it reaches a pause point. */
|
||||
blk_set_disable_request_queuing(blk, true);
|
||||
blk_set_allow_aio_context_change(blk, true);
|
||||
|
||||
if (!block_job_set_speed(job, speed, errp)) {
|
||||
job_early_fail(&job->job);
|
||||
return NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return job;
|
||||
|
||||
fail:
|
||||
job_early_fail(&job->job);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void block_job_iostatus_reset(BlockJob *job)
|
||||
@ -547,3 +540,8 @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err,
|
||||
}
|
||||
return action;
|
||||
}
|
||||
|
||||
AioContext *block_job_get_aio_context(BlockJob *job)
|
||||
{
|
||||
return job->job.aio_context;
|
||||
}
|
||||
|
196
bsd-user/arm/signal.c
Normal file
196
bsd-user/arm/signal.c
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* arm signal functions
|
||||
*
|
||||
* Copyright (c) 2013 Stacey D. Son
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu.h"
|
||||
|
||||
/*
|
||||
* Compare to arm/arm/machdep.c sendsig()
|
||||
* Assumes that target stack frame memory is locked.
|
||||
*/
|
||||
abi_long set_sigtramp_args(CPUARMState *env, int sig,
|
||||
struct target_sigframe *frame,
|
||||
abi_ulong frame_addr,
|
||||
struct target_sigaction *ka)
|
||||
{
|
||||
/*
|
||||
* Arguments to signal handler:
|
||||
* r0 = signal number
|
||||
* r1 = siginfo pointer
|
||||
* r2 = ucontext pointer
|
||||
* r5 = ucontext pointer
|
||||
* pc = signal handler pointer
|
||||
* sp = sigframe struct pointer
|
||||
* lr = sigtramp at base of user stack
|
||||
*/
|
||||
|
||||
env->regs[0] = sig;
|
||||
env->regs[1] = frame_addr +
|
||||
offsetof(struct target_sigframe, sf_si);
|
||||
env->regs[2] = frame_addr +
|
||||
offsetof(struct target_sigframe, sf_uc);
|
||||
|
||||
/* the trampoline uses r5 as the uc address */
|
||||
env->regs[5] = frame_addr +
|
||||
offsetof(struct target_sigframe, sf_uc);
|
||||
env->regs[TARGET_REG_PC] = ka->_sa_handler & ~1;
|
||||
env->regs[TARGET_REG_SP] = frame_addr;
|
||||
env->regs[TARGET_REG_LR] = TARGET_PS_STRINGS - TARGET_SZSIGCODE;
|
||||
/*
|
||||
* Low bit indicates whether or not we're entering thumb mode.
|
||||
*/
|
||||
cpsr_write(env, (ka->_sa_handler & 1) * CPSR_T, CPSR_T, CPSRWriteByInstr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare to arm/arm/machdep.c get_mcontext()
|
||||
* Assumes that the memory is locked if mcp points to user memory.
|
||||
*/
|
||||
abi_long get_mcontext(CPUARMState *env, target_mcontext_t *mcp, int flags)
|
||||
{
|
||||
int err = 0;
|
||||
uint32_t *gr = mcp->__gregs;
|
||||
|
||||
if (mcp->mc_vfp_size != 0 && mcp->mc_vfp_size != sizeof(target_mcontext_vfp_t)) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
|
||||
gr[TARGET_REG_CPSR] = tswap32(cpsr_read(env));
|
||||
if (flags & TARGET_MC_GET_CLEAR_RET) {
|
||||
gr[TARGET_REG_R0] = 0;
|
||||
gr[TARGET_REG_CPSR] &= ~CPSR_C;
|
||||
} else {
|
||||
gr[TARGET_REG_R0] = tswap32(env->regs[0]);
|
||||
}
|
||||
|
||||
gr[TARGET_REG_R1] = tswap32(env->regs[1]);
|
||||
gr[TARGET_REG_R2] = tswap32(env->regs[2]);
|
||||
gr[TARGET_REG_R3] = tswap32(env->regs[3]);
|
||||
gr[TARGET_REG_R4] = tswap32(env->regs[4]);
|
||||
gr[TARGET_REG_R5] = tswap32(env->regs[5]);
|
||||
gr[TARGET_REG_R6] = tswap32(env->regs[6]);
|
||||
gr[TARGET_REG_R7] = tswap32(env->regs[7]);
|
||||
gr[TARGET_REG_R8] = tswap32(env->regs[8]);
|
||||
gr[TARGET_REG_R9] = tswap32(env->regs[9]);
|
||||
gr[TARGET_REG_R10] = tswap32(env->regs[10]);
|
||||
gr[TARGET_REG_R11] = tswap32(env->regs[11]);
|
||||
gr[TARGET_REG_R12] = tswap32(env->regs[12]);
|
||||
|
||||
gr[TARGET_REG_SP] = tswap32(env->regs[13]);
|
||||
gr[TARGET_REG_LR] = tswap32(env->regs[14]);
|
||||
gr[TARGET_REG_PC] = tswap32(env->regs[15]);
|
||||
|
||||
if (mcp->mc_vfp_size != 0 && mcp->mc_vfp_ptr != 0) {
|
||||
/* see get_vfpcontext in sys/arm/arm/exec_machdep.c */
|
||||
target_mcontext_vfp_t *vfp;
|
||||
vfp = lock_user(VERIFY_WRITE, mcp->mc_vfp_ptr, sizeof(*vfp), 0);
|
||||
for (int i = 0; i < 32; i++) {
|
||||
vfp->mcv_reg[i] = tswap64(*aa32_vfp_dreg(env, i));
|
||||
}
|
||||
vfp->mcv_fpscr = tswap32(vfp_get_fpscr(env));
|
||||
unlock_user(vfp, mcp->mc_vfp_ptr, sizeof(*vfp));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Compare to arm/arm/exec_machdep.c set_mcontext() */
|
||||
abi_long set_mcontext(CPUARMState *env, target_mcontext_t *mcp, int srflag)
|
||||
{
|
||||
int err = 0;
|
||||
const uint32_t *gr = mcp->__gregs;
|
||||
uint32_t cpsr, ccpsr = cpsr_read(env);
|
||||
uint32_t fpscr, mask;
|
||||
|
||||
cpsr = tswap32(gr[TARGET_REG_CPSR]);
|
||||
/*
|
||||
* Only allow certain bits to change, reject attempted changes to non-user
|
||||
* bits. In addition, make sure we're headed for user mode and none of the
|
||||
* interrupt bits are set.
|
||||
*/
|
||||
if ((ccpsr & ~CPSR_USER) != (cpsr & ~CPSR_USER)) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
if ((cpsr & CPSR_M) != ARM_CPU_MODE_USR ||
|
||||
(cpsr & (CPSR_I | CPSR_F)) != 0) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* The movs pc,lr instruction that implements the return to userland masks
|
||||
* these bits out.
|
||||
*/
|
||||
mask = cpsr & CPSR_T ? 0x1 : 0x3;
|
||||
|
||||
/*
|
||||
* Make sure that we either have no vfp, or it's the correct size.
|
||||
* FreeBSD just ignores it, though, so maybe we'll need to adjust
|
||||
* things below instead.
|
||||
*/
|
||||
if (mcp->mc_vfp_size != 0 && mcp->mc_vfp_size != sizeof(target_mcontext_vfp_t)) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
|
||||
env->regs[0] = tswap32(gr[TARGET_REG_R0]);
|
||||
env->regs[1] = tswap32(gr[TARGET_REG_R1]);
|
||||
env->regs[2] = tswap32(gr[TARGET_REG_R2]);
|
||||
env->regs[3] = tswap32(gr[TARGET_REG_R3]);
|
||||
env->regs[4] = tswap32(gr[TARGET_REG_R4]);
|
||||
env->regs[5] = tswap32(gr[TARGET_REG_R5]);
|
||||
env->regs[6] = tswap32(gr[TARGET_REG_R6]);
|
||||
env->regs[7] = tswap32(gr[TARGET_REG_R7]);
|
||||
env->regs[8] = tswap32(gr[TARGET_REG_R8]);
|
||||
env->regs[9] = tswap32(gr[TARGET_REG_R9]);
|
||||
env->regs[10] = tswap32(gr[TARGET_REG_R10]);
|
||||
env->regs[11] = tswap32(gr[TARGET_REG_R11]);
|
||||
env->regs[12] = tswap32(gr[TARGET_REG_R12]);
|
||||
|
||||
env->regs[13] = tswap32(gr[TARGET_REG_SP]);
|
||||
env->regs[14] = tswap32(gr[TARGET_REG_LR]);
|
||||
env->regs[15] = tswap32(gr[TARGET_REG_PC] & ~mask);
|
||||
if (mcp->mc_vfp_size != 0 && mcp->mc_vfp_ptr != 0) {
|
||||
/* see set_vfpcontext in sys/arm/arm/exec_machdep.c */
|
||||
target_mcontext_vfp_t *vfp;
|
||||
|
||||
vfp = lock_user(VERIFY_READ, mcp->mc_vfp_ptr, sizeof(*vfp), 1);
|
||||
for (int i = 0; i < 32; i++) {
|
||||
__get_user(*aa32_vfp_dreg(env, i), &vfp->mcv_reg[i]);
|
||||
}
|
||||
__get_user(fpscr, &vfp->mcv_fpscr);
|
||||
vfp_set_fpscr(env, fpscr);
|
||||
unlock_user(vfp, mcp->mc_vfp_ptr, sizeof(target_ucontext_t));
|
||||
|
||||
/*
|
||||
* linux-user sets fpexc, fpinst and fpinst2, but these aren't in
|
||||
* FreeBSD's mcontext, what to do?
|
||||
*/
|
||||
}
|
||||
cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC, CPSRWriteByInstr);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Compare to arm/arm/machdep.c sys_sigreturn() */
|
||||
abi_long get_ucontext_sigreturn(CPUARMState *env, abi_ulong target_sf,
|
||||
abi_ulong *target_uc)
|
||||
{
|
||||
*target_uc = target_sf;
|
||||
|
||||
return 0;
|
||||
}
|
28
bsd-user/arm/target_arch.h
Normal file
28
bsd-user/arm/target_arch.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* ARM 32-bit specific prototypes for bsd-user
|
||||
*
|
||||
* Copyright (c) 2013 Stacey D. Son
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _TARGET_ARCH_H_
|
||||
#define _TARGET_ARCH_H_
|
||||
|
||||
#include "qemu.h"
|
||||
|
||||
void target_cpu_set_tls(CPUARMState *env, target_ulong newtls);
|
||||
target_ulong target_cpu_get_tls(CPUARMState *env);
|
||||
|
||||
#endif /* !_TARGET_ARCH_H_ */
|
39
bsd-user/arm/target_arch_cpu.c
Normal file
39
bsd-user/arm/target_arch_cpu.c
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* arm cpu related code
|
||||
*
|
||||
* Copyright (c) 2013 Stacey D. Son
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "target_arch.h"
|
||||
|
||||
void target_cpu_set_tls(CPUARMState *env, target_ulong newtls)
|
||||
{
|
||||
if (access_secure_reg(env)) {
|
||||
env->cp15.tpidrurw_s = newtls;
|
||||
env->cp15.tpidruro_s = newtls;
|
||||
return;
|
||||
}
|
||||
|
||||
env->cp15.tpidr_el[0] = newtls;
|
||||
env->cp15.tpidrro_el[0] = newtls;
|
||||
}
|
||||
|
||||
target_ulong target_cpu_get_tls(CPUARMState *env)
|
||||
{
|
||||
if (access_secure_reg(env)) {
|
||||
return env->cp15.tpidruro_s;
|
||||
}
|
||||
return env->cp15.tpidrro_el[0];
|
||||
}
|
211
bsd-user/arm/target_arch_cpu.h
Normal file
211
bsd-user/arm/target_arch_cpu.h
Normal file
@ -0,0 +1,211 @@
|
||||
/*
|
||||
* arm cpu init and loop
|
||||
*
|
||||
* Copyright (c) 2013 Stacey D. Son
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _TARGET_ARCH_CPU_H_
|
||||
#define _TARGET_ARCH_CPU_H_
|
||||
|
||||
#include "target_arch.h"
|
||||
|
||||
#define TARGET_DEFAULT_CPU_MODEL "any"
|
||||
|
||||
static inline void target_cpu_init(CPUARMState *env,
|
||||
struct target_pt_regs *regs)
|
||||
{
|
||||
int i;
|
||||
|
||||
cpsr_write(env, regs->uregs[16], CPSR_USER | CPSR_EXEC,
|
||||
CPSRWriteByInstr);
|
||||
for (i = 0; i < 16; i++) {
|
||||
env->regs[i] = regs->uregs[i];
|
||||
}
|
||||
}
|
||||
|
||||
static inline void target_cpu_loop(CPUARMState *env)
|
||||
{
|
||||
int trapnr;
|
||||
target_siginfo_t info;
|
||||
unsigned int n;
|
||||
CPUState *cs = env_cpu(env);
|
||||
|
||||
for (;;) {
|
||||
cpu_exec_start(cs);
|
||||
trapnr = cpu_exec(cs);
|
||||
cpu_exec_end(cs);
|
||||
process_queued_cpu_work(cs);
|
||||
switch (trapnr) {
|
||||
case EXCP_UDEF:
|
||||
{
|
||||
/* See arm/arm/undefined.c undefinedinstruction(); */
|
||||
info.si_addr = env->regs[15];
|
||||
|
||||
/* illegal instruction */
|
||||
info.si_signo = TARGET_SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_ILL_ILLOPC;
|
||||
queue_signal(env, info.si_signo, &info);
|
||||
|
||||
/* TODO: What about instruction emulation? */
|
||||
}
|
||||
break;
|
||||
case EXCP_SWI:
|
||||
case EXCP_BKPT:
|
||||
{
|
||||
/*
|
||||
* system call
|
||||
* See arm/arm/trap.c cpu_fetch_syscall_args()
|
||||
*/
|
||||
if (trapnr == EXCP_BKPT) {
|
||||
if (env->thumb) {
|
||||
env->regs[15] += 2;
|
||||
} else {
|
||||
env->regs[15] += 4;
|
||||
}
|
||||
}
|
||||
n = env->regs[7];
|
||||
if (bsd_type == target_freebsd) {
|
||||
int ret;
|
||||
abi_ulong params = get_sp_from_cpustate(env);
|
||||
int32_t syscall_nr = n;
|
||||
int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
|
||||
|
||||
/* See arm/arm/trap.c cpu_fetch_syscall_args() */
|
||||
if (syscall_nr == TARGET_FREEBSD_NR_syscall) {
|
||||
syscall_nr = env->regs[0];
|
||||
arg1 = env->regs[1];
|
||||
arg2 = env->regs[2];
|
||||
arg3 = env->regs[3];
|
||||
get_user_s32(arg4, params);
|
||||
params += sizeof(int32_t);
|
||||
get_user_s32(arg5, params);
|
||||
params += sizeof(int32_t);
|
||||
get_user_s32(arg6, params);
|
||||
params += sizeof(int32_t);
|
||||
get_user_s32(arg7, params);
|
||||
arg8 = 0;
|
||||
} else if (syscall_nr == TARGET_FREEBSD_NR___syscall) {
|
||||
syscall_nr = env->regs[0];
|
||||
arg1 = env->regs[2];
|
||||
arg2 = env->regs[3];
|
||||
get_user_s32(arg3, params);
|
||||
params += sizeof(int32_t);
|
||||
get_user_s32(arg4, params);
|
||||
params += sizeof(int32_t);
|
||||
get_user_s32(arg5, params);
|
||||
params += sizeof(int32_t);
|
||||
get_user_s32(arg6, params);
|
||||
arg7 = 0;
|
||||
arg8 = 0;
|
||||
} else {
|
||||
arg1 = env->regs[0];
|
||||
arg2 = env->regs[1];
|
||||
arg3 = env->regs[2];
|
||||
arg4 = env->regs[3];
|
||||
get_user_s32(arg5, params);
|
||||
params += sizeof(int32_t);
|
||||
get_user_s32(arg6, params);
|
||||
params += sizeof(int32_t);
|
||||
get_user_s32(arg7, params);
|
||||
params += sizeof(int32_t);
|
||||
get_user_s32(arg8, params);
|
||||
}
|
||||
ret = do_freebsd_syscall(env, syscall_nr, arg1, arg2, arg3,
|
||||
arg4, arg5, arg6, arg7, arg8);
|
||||
/*
|
||||
* Compare to arm/arm/vm_machdep.c
|
||||
* cpu_set_syscall_retval()
|
||||
*/
|
||||
if (-TARGET_EJUSTRETURN == ret) {
|
||||
/*
|
||||
* Returning from a successful sigreturn syscall.
|
||||
* Avoid clobbering register state.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
if (-TARGET_ERESTART == ret) {
|
||||
env->regs[15] -= env->thumb ? 2 : 4;
|
||||
break;
|
||||
}
|
||||
if ((unsigned int)ret >= (unsigned int)(-515)) {
|
||||
ret = -ret;
|
||||
cpsr_write(env, CPSR_C, CPSR_C, CPSRWriteByInstr);
|
||||
env->regs[0] = ret;
|
||||
} else {
|
||||
cpsr_write(env, 0, CPSR_C, CPSRWriteByInstr);
|
||||
env->regs[0] = ret; /* XXX need to handle lseek()? */
|
||||
/* env->regs[1] = 0; */
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "qemu: bsd_type (= %d) syscall "
|
||||
"not supported\n", bsd_type);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EXCP_INTERRUPT:
|
||||
/* just indicate that signals should be handled asap */
|
||||
break;
|
||||
case EXCP_PREFETCH_ABORT:
|
||||
/* See arm/arm/trap.c prefetch_abort_handler() */
|
||||
case EXCP_DATA_ABORT:
|
||||
/* See arm/arm/trap.c data_abort_handler() */
|
||||
info.si_signo = TARGET_SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
/* XXX: check env->error_code */
|
||||
info.si_code = 0;
|
||||
info.si_addr = env->exception.vaddress;
|
||||
queue_signal(env, info.si_signo, &info);
|
||||
break;
|
||||
case EXCP_DEBUG:
|
||||
{
|
||||
|
||||
info.si_signo = TARGET_SIGTRAP;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_TRAP_BRKPT;
|
||||
info.si_addr = env->exception.vaddress;
|
||||
queue_signal(env, info.si_signo, &info);
|
||||
}
|
||||
break;
|
||||
case EXCP_ATOMIC:
|
||||
cpu_exec_step_atomic(cs);
|
||||
break;
|
||||
case EXCP_YIELD:
|
||||
/* nothing to do here for user-mode, just resume guest code */
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
|
||||
trapnr);
|
||||
cpu_dump_state(cs, stderr, 0);
|
||||
abort();
|
||||
} /* switch() */
|
||||
process_pending_signals(env);
|
||||
} /* for (;;) */
|
||||
}
|
||||
|
||||
static inline void target_cpu_clone_regs(CPUARMState *env, target_ulong newsp)
|
||||
{
|
||||
if (newsp) {
|
||||
env->regs[13] = newsp;
|
||||
}
|
||||
env->regs[0] = 0;
|
||||
}
|
||||
|
||||
static inline void target_cpu_reset(CPUArchState *cpu)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* !_TARGET_ARCH_CPU_H */
|
128
bsd-user/arm/target_arch_elf.h
Normal file
128
bsd-user/arm/target_arch_elf.h
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* arm ELF definitions
|
||||
*
|
||||
* Copyright (c) 2013 Stacey D. Son
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef _TARGET_ARCH_ELF_H_
|
||||
#define _TARGET_ARCH_ELF_H_
|
||||
|
||||
#define ELF_START_MMAP 0x80000000
|
||||
#define ELF_ET_DYN_LOAD_ADDR 0x500000
|
||||
|
||||
#define elf_check_arch(x) ((x) == EM_ARM)
|
||||
|
||||
#define ELF_CLASS ELFCLASS32
|
||||
#define ELF_DATA ELFDATA2LSB
|
||||
#define ELF_ARCH EM_ARM
|
||||
|
||||
#define USE_ELF_CORE_DUMP
|
||||
#define ELF_EXEC_PAGESIZE 4096
|
||||
|
||||
#define ELF_HWCAP get_elf_hwcap()
|
||||
#define ELF_HWCAP2 get_elf_hwcap2()
|
||||
|
||||
#define GET_FEATURE(feat, hwcap) \
|
||||
do { if (arm_feature(&cpu->env, feat)) { hwcaps |= hwcap; } } while (0)
|
||||
|
||||
#define GET_FEATURE_ID(feat, hwcap) \
|
||||
do { if (cpu_isar_feature(feat, cpu)) { hwcaps |= hwcap; } } while (0)
|
||||
|
||||
enum {
|
||||
ARM_HWCAP_ARM_SWP = 1 << 0,
|
||||
ARM_HWCAP_ARM_HALF = 1 << 1,
|
||||
ARM_HWCAP_ARM_THUMB = 1 << 2,
|
||||
ARM_HWCAP_ARM_26BIT = 1 << 3,
|
||||
ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
|
||||
ARM_HWCAP_ARM_FPA = 1 << 5,
|
||||
ARM_HWCAP_ARM_VFP = 1 << 6,
|
||||
ARM_HWCAP_ARM_EDSP = 1 << 7,
|
||||
ARM_HWCAP_ARM_JAVA = 1 << 8,
|
||||
ARM_HWCAP_ARM_IWMMXT = 1 << 9,
|
||||
ARM_HWCAP_ARM_CRUNCH = 1 << 10,
|
||||
ARM_HWCAP_ARM_THUMBEE = 1 << 11,
|
||||
ARM_HWCAP_ARM_NEON = 1 << 12,
|
||||
ARM_HWCAP_ARM_VFPv3 = 1 << 13,
|
||||
ARM_HWCAP_ARM_VFPv3D16 = 1 << 14,
|
||||
ARM_HWCAP_ARM_TLS = 1 << 15,
|
||||
ARM_HWCAP_ARM_VFPv4 = 1 << 16,
|
||||
ARM_HWCAP_ARM_IDIVA = 1 << 17,
|
||||
ARM_HWCAP_ARM_IDIVT = 1 << 18,
|
||||
ARM_HWCAP_ARM_VFPD32 = 1 << 19,
|
||||
ARM_HWCAP_ARM_LPAE = 1 << 20,
|
||||
ARM_HWCAP_ARM_EVTSTRM = 1 << 21,
|
||||
};
|
||||
|
||||
enum {
|
||||
ARM_HWCAP2_ARM_AES = 1 << 0,
|
||||
ARM_HWCAP2_ARM_PMULL = 1 << 1,
|
||||
ARM_HWCAP2_ARM_SHA1 = 1 << 2,
|
||||
ARM_HWCAP2_ARM_SHA2 = 1 << 3,
|
||||
ARM_HWCAP2_ARM_CRC32 = 1 << 4,
|
||||
};
|
||||
|
||||
static uint32_t get_elf_hwcap(void)
|
||||
{
|
||||
ARMCPU *cpu = ARM_CPU(thread_cpu);
|
||||
uint32_t hwcaps = 0;
|
||||
|
||||
hwcaps |= ARM_HWCAP_ARM_SWP;
|
||||
hwcaps |= ARM_HWCAP_ARM_HALF;
|
||||
hwcaps |= ARM_HWCAP_ARM_THUMB;
|
||||
hwcaps |= ARM_HWCAP_ARM_FAST_MULT;
|
||||
|
||||
/* probe for the extra features */
|
||||
/* EDSP is in v5TE and above */
|
||||
GET_FEATURE(ARM_FEATURE_V5, ARM_HWCAP_ARM_EDSP);
|
||||
GET_FEATURE(ARM_FEATURE_IWMMXT, ARM_HWCAP_ARM_IWMMXT);
|
||||
GET_FEATURE(ARM_FEATURE_THUMB2EE, ARM_HWCAP_ARM_THUMBEE);
|
||||
GET_FEATURE(ARM_FEATURE_NEON, ARM_HWCAP_ARM_NEON);
|
||||
GET_FEATURE(ARM_FEATURE_V6K, ARM_HWCAP_ARM_TLS);
|
||||
GET_FEATURE(ARM_FEATURE_LPAE, ARM_HWCAP_ARM_LPAE);
|
||||
GET_FEATURE_ID(aa32_arm_div, ARM_HWCAP_ARM_IDIVA);
|
||||
GET_FEATURE_ID(aa32_thumb_div, ARM_HWCAP_ARM_IDIVT);
|
||||
GET_FEATURE_ID(aa32_vfp, ARM_HWCAP_ARM_VFP);
|
||||
|
||||
if (cpu_isar_feature(aa32_fpsp_v3, cpu) ||
|
||||
cpu_isar_feature(aa32_fpdp_v3, cpu)) {
|
||||
hwcaps |= ARM_HWCAP_ARM_VFPv3;
|
||||
if (cpu_isar_feature(aa32_simd_r32, cpu)) {
|
||||
hwcaps |= ARM_HWCAP_ARM_VFPD32;
|
||||
} else {
|
||||
hwcaps |= ARM_HWCAP_ARM_VFPv3D16;
|
||||
}
|
||||
}
|
||||
GET_FEATURE_ID(aa32_simdfmac, ARM_HWCAP_ARM_VFPv4);
|
||||
|
||||
return hwcaps;
|
||||
}
|
||||
|
||||
static uint32_t get_elf_hwcap2(void)
|
||||
{
|
||||
ARMCPU *cpu = ARM_CPU(thread_cpu);
|
||||
uint32_t hwcaps = 0;
|
||||
|
||||
GET_FEATURE_ID(aa32_aes, ARM_HWCAP2_ARM_AES);
|
||||
GET_FEATURE_ID(aa32_pmull, ARM_HWCAP2_ARM_PMULL);
|
||||
GET_FEATURE_ID(aa32_sha1, ARM_HWCAP2_ARM_SHA1);
|
||||
GET_FEATURE_ID(aa32_sha2, ARM_HWCAP2_ARM_SHA2);
|
||||
GET_FEATURE_ID(aa32_crc32, ARM_HWCAP2_ARM_CRC32);
|
||||
return hwcaps;
|
||||
}
|
||||
|
||||
#undef GET_FEATURE
|
||||
#undef GET_FEATURE_ID
|
||||
|
||||
#endif /* _TARGET_ARCH_ELF_H_ */
|
60
bsd-user/arm/target_arch_reg.h
Normal file
60
bsd-user/arm/target_arch_reg.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* FreeBSD arm register structures
|
||||
*
|
||||
* Copyright (c) 2015 Stacey Son
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _TARGET_ARCH_REG_H_
|
||||
#define _TARGET_ARCH_REG_H_
|
||||
|
||||
/* See sys/arm/include/reg.h */
|
||||
typedef struct target_reg {
|
||||
uint32_t r[13];
|
||||
uint32_t r_sp;
|
||||
uint32_t r_lr;
|
||||
uint32_t r_pc;
|
||||
uint32_t r_cpsr;
|
||||
} target_reg_t;
|
||||
|
||||
typedef struct target_fp_reg {
|
||||
uint32_t fp_exponent;
|
||||
uint32_t fp_mantissa_hi;
|
||||
u_int32_t fp_mantissa_lo;
|
||||
} target_fp_reg_t;
|
||||
|
||||
typedef struct target_fpreg {
|
||||
uint32_t fpr_fpsr;
|
||||
target_fp_reg_t fpr[8];
|
||||
} target_fpreg_t;
|
||||
|
||||
#define tswapreg(ptr) tswapal(ptr)
|
||||
|
||||
static inline void target_copy_regs(target_reg_t *regs, const CPUARMState *env)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 13; i++) {
|
||||
regs->r[i] = tswapreg(env->regs[i + 1]);
|
||||
}
|
||||
regs->r_sp = tswapreg(env->regs[13]);
|
||||
regs->r_lr = tswapreg(env->regs[14]);
|
||||
regs->r_pc = tswapreg(env->regs[15]);
|
||||
regs->r_cpsr = tswapreg(cpsr_read((CPUARMState *)env));
|
||||
}
|
||||
|
||||
#undef tswapreg
|
||||
|
||||
#endif /* !_TARGET_ARCH_REG_H_ */
|
88
bsd-user/arm/target_arch_signal.h
Normal file
88
bsd-user/arm/target_arch_signal.h
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* arm signal definitions
|
||||
*
|
||||
* Copyright (c) 2013 Stacey D. Son
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef _TARGET_ARCH_SIGNAL_H_
|
||||
#define _TARGET_ARCH_SIGNAL_H_
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
#define TARGET_REG_R0 0
|
||||
#define TARGET_REG_R1 1
|
||||
#define TARGET_REG_R2 2
|
||||
#define TARGET_REG_R3 3
|
||||
#define TARGET_REG_R4 4
|
||||
#define TARGET_REG_R5 5
|
||||
#define TARGET_REG_R6 6
|
||||
#define TARGET_REG_R7 7
|
||||
#define TARGET_REG_R8 8
|
||||
#define TARGET_REG_R9 9
|
||||
#define TARGET_REG_R10 10
|
||||
#define TARGET_REG_R11 11
|
||||
#define TARGET_REG_R12 12
|
||||
#define TARGET_REG_R13 13
|
||||
#define TARGET_REG_R14 14
|
||||
#define TARGET_REG_R15 15
|
||||
#define TARGET_REG_CPSR 16
|
||||
#define TARGET__NGREG 17
|
||||
/* Convenience synonyms */
|
||||
#define TARGET_REG_FP TARGET_REG_R11
|
||||
#define TARGET_REG_SP TARGET_REG_R13
|
||||
#define TARGET_REG_LR TARGET_REG_R14
|
||||
#define TARGET_REG_PC TARGET_REG_R15
|
||||
|
||||
#define TARGET_INSN_SIZE 4 /* arm instruction size */
|
||||
|
||||
/* Size of the signal trampolin code. See _sigtramp(). */
|
||||
#define TARGET_SZSIGCODE ((abi_ulong)(9 * TARGET_INSN_SIZE))
|
||||
|
||||
/* compare to arm/include/_limits.h */
|
||||
#define TARGET_MINSIGSTKSZ (1024 * 4) /* min sig stack size */
|
||||
#define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768) /* recommended size */
|
||||
|
||||
/*
|
||||
* Floating point register state
|
||||
*/
|
||||
typedef struct target_mcontext_vfp {
|
||||
abi_ullong mcv_reg[32];
|
||||
abi_ulong mcv_fpscr;
|
||||
} target_mcontext_vfp_t;
|
||||
|
||||
typedef struct target_mcontext {
|
||||
abi_uint __gregs[TARGET__NGREG];
|
||||
|
||||
/*
|
||||
* Originally, rest of this structure was named __fpu, 35 * 4 bytes
|
||||
* long, never accessed from kernel.
|
||||
*/
|
||||
abi_ulong mc_vfp_size;
|
||||
abi_ptr mc_vfp_ptr;
|
||||
abi_int mc_spare[33];
|
||||
} target_mcontext_t;
|
||||
|
||||
#define TARGET_MCONTEXT_SIZE 208
|
||||
#define TARGET_UCONTEXT_SIZE 260
|
||||
|
||||
#include "target_os_ucontext.h"
|
||||
|
||||
struct target_sigframe {
|
||||
target_siginfo_t sf_si; /* saved siginfo */
|
||||
target_ucontext_t sf_uc; /* saved ucontext */
|
||||
target_mcontext_vfp_t sf_vfp; /* actual saved VFP context */
|
||||
};
|
||||
|
||||
#endif /* !_TARGET_ARCH_SIGNAL_H_ */
|
49
bsd-user/arm/target_arch_sigtramp.h
Normal file
49
bsd-user/arm/target_arch_sigtramp.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* arm sysarch() system call emulation
|
||||
*
|
||||
* Copyright (c) 2013 Stacey D. Son
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _TARGET_ARCH_SIGTRAMP_H_
|
||||
#define _TARGET_ARCH_SIGTRAMP_H_
|
||||
|
||||
/* Compare to arm/arm/locore.S ENTRY_NP(sigcode) */
|
||||
static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
|
||||
unsigned sys_sigreturn)
|
||||
{
|
||||
int i;
|
||||
uint32_t sys_exit = TARGET_FREEBSD_NR_exit;
|
||||
uint32_t sigtramp_code[] = {
|
||||
/* 1 */ 0xE1A0000D, /* mov r0, sp */
|
||||
/* 2 */ 0xE2800000 + sigf_uc, /* add r0, r0, #SIGF_UC */
|
||||
/* 3 */ 0xE59F700C, /* ldr r7, [pc, #12] */
|
||||
/* 4 */ 0xEF000000 + sys_sigreturn, /* swi (SYS_sigreturn) */
|
||||
/* 5 */ 0xE59F7008, /* ldr r7, [pc, #8] */
|
||||
/* 6 */ 0xEF000000 + sys_exit, /* swi (SYS_exit)*/
|
||||
/* 7 */ 0xEAFFFFFA, /* b . -16 */
|
||||
/* 8 */ sys_sigreturn,
|
||||
/* 9 */ sys_exit
|
||||
};
|
||||
|
||||
G_STATIC_ASSERT(sizeof(sigtramp_code) == TARGET_SZSIGCODE);
|
||||
|
||||
for (i = 0; i < 9; i++) {
|
||||
tswap32s(&sigtramp_code[i]);
|
||||
}
|
||||
|
||||
return memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE);
|
||||
}
|
||||
#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
|
@ -17,8 +17,8 @@
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef BSD_USER_ARCH_SYSARCH_H_
|
||||
#define BSD_USER_ARCH_SYSARCH_H_
|
||||
#ifndef _TARGET_ARCH_SYSARCH_H_
|
||||
#define _TARGET_ARCH_SYSARCH_H_
|
||||
|
||||
#include "target_syscall.h"
|
||||
#include "target_arch.h"
|
||||
@ -75,4 +75,4 @@ static inline void do_freebsd_arch_print_sysarch(
|
||||
}
|
||||
}
|
||||
|
||||
#endif /*!BSD_USER_ARCH_SYSARCH_H_ */
|
||||
#endif /*!_TARGET_ARCH_SYSARCH_H_ */
|
||||
|
82
bsd-user/arm/target_arch_thread.h
Normal file
82
bsd-user/arm/target_arch_thread.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* arm thread support
|
||||
*
|
||||
* Copyright (c) 2013 Stacey D. Son
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef _TARGET_ARCH_THREAD_H_
|
||||
#define _TARGET_ARCH_THREAD_H_
|
||||
|
||||
/* Compare to arm/arm/vm_machdep.c cpu_set_upcall_kse() */
|
||||
static inline void target_thread_set_upcall(CPUARMState *env, abi_ulong entry,
|
||||
abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size)
|
||||
{
|
||||
abi_ulong sp;
|
||||
|
||||
/*
|
||||
* Make sure the stack is properly aligned.
|
||||
* arm/include/param.h (STACKLIGN() macro)
|
||||
*/
|
||||
sp = (u_int)(stack_base + stack_size) & ~0x7;
|
||||
|
||||
/* sp = stack base */
|
||||
env->regs[13] = sp;
|
||||
/* pc = start function entry */
|
||||
env->regs[15] = entry & 0xfffffffe;
|
||||
/* r0 = arg */
|
||||
env->regs[0] = arg;
|
||||
env->spsr = ARM_CPU_MODE_USR;
|
||||
/*
|
||||
* Thumb mode is encoded by the low bit in the entry point (since ARM can't
|
||||
* execute at odd addresses). When it's set, set the Thumb bit (T) in the
|
||||
* CPSR.
|
||||
*/
|
||||
cpsr_write(env, (entry & 1) * CPSR_T, CPSR_T, CPSRWriteByInstr);
|
||||
}
|
||||
|
||||
static inline void target_thread_init(struct target_pt_regs *regs,
|
||||
struct image_info *infop)
|
||||
{
|
||||
abi_long stack = infop->start_stack;
|
||||
memset(regs, 0, sizeof(*regs));
|
||||
regs->ARM_cpsr = ARM_CPU_MODE_USR;
|
||||
/*
|
||||
* Thumb mode is encoded by the low bit in the entry point (since ARM can't
|
||||
* execute at odd addresses). When it's set, set the Thumb bit (T) in the
|
||||
* CPSR.
|
||||
*/
|
||||
if (infop->entry & 1) {
|
||||
regs->ARM_cpsr |= CPSR_T;
|
||||
}
|
||||
regs->ARM_pc = infop->entry & 0xfffffffe;
|
||||
regs->ARM_sp = stack;
|
||||
if (bsd_type == target_freebsd) {
|
||||
regs->ARM_lr = infop->entry & 0xfffffffe;
|
||||
}
|
||||
/*
|
||||
* FreeBSD kernel passes the ps_strings pointer in r0. This is used by some
|
||||
* programs to set status messages that we see in ps. bsd-user doesn't
|
||||
* support that functionality, so it's ignored. When set to 0, FreeBSD's csu
|
||||
* code ignores it. For the static case, r1 and r2 are effectively ignored
|
||||
* by the csu __startup() routine. For the dynamic case, rtld saves r0 but
|
||||
* generates r1 and r2 and passes them into the csu _startup.
|
||||
*
|
||||
* r0 ps_strings 0 passed since ps arg setting not supported
|
||||
* r1 obj_main ignored by _start(), so 0 passed
|
||||
* r2 cleanup generated by rtld or ignored by _start(), so 0 passed
|
||||
*/
|
||||
}
|
||||
|
||||
#endif /* !_TARGET_ARCH_THREAD_H_ */
|
48
bsd-user/arm/target_arch_vmparam.h
Normal file
48
bsd-user/arm/target_arch_vmparam.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* arm VM parameters definitions
|
||||
*
|
||||
* Copyright (c) 2013 Stacey D. Son
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef _TARGET_ARCH_VMPARAM_H_
|
||||
#define _TARGET_ARCH_VMPARAM_H_
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
/* compare to sys/arm/include/vmparam.h */
|
||||
#define TARGET_MAXTSIZ (64 * MiB) /* max text size */
|
||||
#define TARGET_DFLDSIZ (128 * MiB) /* initial data size limit */
|
||||
#define TARGET_MAXDSIZ (512 * MiB) /* max data size */
|
||||
#define TARGET_DFLSSIZ (4 * MiB) /* initial stack size limit */
|
||||
#define TARGET_MAXSSIZ (64 * MiB) /* max stack size */
|
||||
#define TARGET_SGROWSIZ (128 * KiB) /* amount to grow stack */
|
||||
|
||||
#define TARGET_RESERVED_VA 0xf7000000
|
||||
|
||||
/* KERNBASE - 512 MB */
|
||||
#define TARGET_VM_MAXUSER_ADDRESS (0xc0000000 - (512 * MiB))
|
||||
#define TARGET_USRSTACK TARGET_VM_MAXUSER_ADDRESS
|
||||
|
||||
static inline abi_ulong get_sp_from_cpustate(CPUARMState *state)
|
||||
{
|
||||
return state->regs[13]; /* sp */
|
||||
}
|
||||
|
||||
static inline void set_second_rval(CPUARMState *state, abi_ulong retval2)
|
||||
{
|
||||
state->regs[1] = retval2;
|
||||
}
|
||||
|
||||
#endif /* ! _TARGET_ARCH_VMPARAM_H_ */
|
@ -1,5 +1,24 @@
|
||||
#ifndef BSD_USER_ARCH_SYSCALL_H_
|
||||
#define BSD_USER_ARCH_SYSCALL_H_
|
||||
/*
|
||||
* arm cpu system call stubs
|
||||
*
|
||||
* Copyright (c) 2013 Stacey D. Son
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _TARGET_ARCH_SYSCALL_H_
|
||||
#define _TARGET_ARCH_SYSCALL_H_
|
||||
|
||||
struct target_pt_regs {
|
||||
abi_long uregs[17];
|
||||
@ -31,6 +50,6 @@ struct target_pt_regs {
|
||||
#define TARGET_FREEBSD_ARM_GET_TP 3
|
||||
|
||||
#define TARGET_HW_MACHINE "arm"
|
||||
#define TARGET_HW_MACHINE_ARCH "armv6"
|
||||
#define TARGET_HW_MACHINE_ARCH "armv7"
|
||||
|
||||
#endif /* !BSD_USER_ARCH_SYSCALL_H_ */
|
||||
#endif /* !_TARGET_ARCH_SYSCALL_H_ */
|
||||
|
@ -1,9 +1,6 @@
|
||||
#ifndef _TARGET_OS_SIGNAL_H_
|
||||
#define _TARGET_OS_SIGNAL_H_
|
||||
|
||||
/* FreeBSD's sys/ucontext.h defines this */
|
||||
#define TARGET_MC_GET_CLEAR_RET 0x0001
|
||||
|
||||
#include "target_os_siginfo.h"
|
||||
#include "target_arch_signal.h"
|
||||
|
||||
|
44
bsd-user/freebsd/target_os_ucontext.h
Normal file
44
bsd-user/freebsd/target_os_ucontext.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* FreeBSD has a common ucontext definition for all architectures.
|
||||
*
|
||||
* Copyright 2021 Warner Losh <imp@bsdimp.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause
|
||||
*/
|
||||
#ifndef TARGET_OS_UCONTEXT_H
|
||||
#define TARGET_OS_UCONTEXT_H
|
||||
|
||||
/*
|
||||
* Defines the common bits for all of FreeBSD's architectures. Has to be
|
||||
* included AFTER the MD target_mcontext_t is defined, however, so can't
|
||||
* be in the grab-bag that is target_os_signal.h.
|
||||
*/
|
||||
|
||||
/* See FreeBSD's sys/ucontext.h */
|
||||
#define TARGET_MC_GET_CLEAR_RET 0x0001
|
||||
|
||||
/* FreeBSD's sys/_ucontext.h structures */
|
||||
typedef struct target_ucontext {
|
||||
target_sigset_t uc_sigmask;
|
||||
target_mcontext_t uc_mcontext;
|
||||
abi_ulong uc_link;
|
||||
target_stack_t uc_stack;
|
||||
int32_t uc_flags;
|
||||
int32_t __spare__[4];
|
||||
} target_ucontext_t;
|
||||
|
||||
G_STATIC_ASSERT(TARGET_MCONTEXT_SIZE == sizeof(target_mcontext_t));
|
||||
G_STATIC_ASSERT(TARGET_UCONTEXT_SIZE == sizeof(target_ucontext_t));
|
||||
|
||||
struct target_sigframe;
|
||||
|
||||
abi_long set_sigtramp_args(CPUArchState *env, int sig,
|
||||
struct target_sigframe *frame,
|
||||
abi_ulong frame_addr,
|
||||
struct target_sigaction *ka);
|
||||
abi_long get_mcontext(CPUArchState *regs, target_mcontext_t *mcp, int flags);
|
||||
abi_long set_mcontext(CPUArchState *regs, target_mcontext_t *mcp, int srflag);
|
||||
abi_long get_ucontext_sigreturn(CPUArchState *regs, abi_ulong target_sf,
|
||||
abi_ulong *target_uc);
|
||||
|
||||
#endif /* TARGET_OS_UCONTEXT_H */
|
55
bsd-user/i386/signal.c
Normal file
55
bsd-user/i386/signal.c
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* i386 dependent signal definitions
|
||||
*
|
||||
* Copyright (c) 2013 Stacey D. Son
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu.h"
|
||||
|
||||
/*
|
||||
* Compare to i386/i386/machdep.c sendsig()
|
||||
* Assumes that target stack frame memory is locked.
|
||||
*/
|
||||
abi_long set_sigtramp_args(CPUX86State *env, int sig,
|
||||
struct target_sigframe *frame,
|
||||
abi_ulong frame_addr,
|
||||
struct target_sigaction *ka)
|
||||
{
|
||||
/* XXX return -TARGET_EOPNOTSUPP; */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compare to i386/i386/machdep.c get_mcontext() */
|
||||
abi_long get_mcontext(CPUX86State *regs, target_mcontext_t *mcp, int flags)
|
||||
{
|
||||
/* XXX */
|
||||
return -TARGET_EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* Compare to i386/i386/machdep.c set_mcontext() */
|
||||
abi_long set_mcontext(CPUX86State *regs, target_mcontext_t *mcp, int srflag)
|
||||
{
|
||||
/* XXX */
|
||||
return -TARGET_EOPNOTSUPP;
|
||||
}
|
||||
|
||||
abi_long get_ucontext_sigreturn(CPUX86State *regs, abi_ulong target_sf,
|
||||
abi_ulong *target_uc)
|
||||
{
|
||||
/* XXX */
|
||||
*target_uc = 0;
|
||||
return -TARGET_EOPNOTSUPP;
|
||||
}
|
@ -27,21 +27,56 @@
|
||||
#define TARGET_MINSIGSTKSZ (512 * 4) /* min sig stack size */
|
||||
#define TARGET_SIGSTKSZ (MINSIGSTKSZ + 32768) /* recommended size */
|
||||
|
||||
struct target_sigcontext {
|
||||
/* to be added */
|
||||
};
|
||||
|
||||
typedef struct target_mcontext {
|
||||
abi_ulong mc_onstack; /* XXX - sigcontext compat. */
|
||||
abi_ulong mc_gs; /* machine state (struct trapframe) */
|
||||
abi_ulong mc_fs;
|
||||
abi_ulong mc_es;
|
||||
abi_ulong mc_ds;
|
||||
abi_ulong mc_edi;
|
||||
abi_ulong mc_esi;
|
||||
abi_ulong mc_ebp;
|
||||
abi_ulong mc_isp;
|
||||
abi_ulong mc_ebx;
|
||||
abi_ulong mc_edx;
|
||||
abi_ulong mc_ecx;
|
||||
abi_ulong mc_eax;
|
||||
abi_ulong mc_trapno;
|
||||
abi_ulong mc_err;
|
||||
abi_ulong mc_eip;
|
||||
abi_ulong mc_cs;
|
||||
abi_ulong mc_eflags;
|
||||
abi_ulong mc_esp;
|
||||
abi_ulong mc_ss;
|
||||
|
||||
int32_t mc_len; /* sizeof(mcontext_t) */
|
||||
#define _MC_FPFMT_NODEV 0x10000 /* device not present or configured */
|
||||
#define _MC_FPFMT_387 0x10001
|
||||
#define _MC_FPFMT_XMM 0x10002
|
||||
int32_t mc_fpformat;
|
||||
#define _MC_FPOWNED_NONE 0x20000 /* FP state not used */
|
||||
#define _MC_FPOWNED_FPU 0x20001 /* FP state came from FPU */
|
||||
#define _MC_FPOWNED_PCB 0x20002 /* FP state came from PCB */
|
||||
int32_t mc_ownedfp;
|
||||
abi_ulong mc_flags;
|
||||
/*
|
||||
* See <machine/npx.h> for the internals of mc_fpstate[].
|
||||
*/
|
||||
int32_t mc_fpstate[128] __aligned(16);
|
||||
|
||||
abi_ulong mc_fsbase;
|
||||
abi_ulong mc_gsbase;
|
||||
|
||||
abi_ulong mc_xfpustate;
|
||||
abi_ulong mc_xfpustate_len;
|
||||
|
||||
int32_t mc_spare2[4];
|
||||
} target_mcontext_t;
|
||||
|
||||
typedef struct target_ucontext {
|
||||
target_sigset_t uc_sigmask;
|
||||
target_mcontext_t uc_mcontext;
|
||||
abi_ulong uc_link;
|
||||
target_stack_t uc_stack;
|
||||
int32_t uc_flags;
|
||||
int32_t __spare__[4];
|
||||
} target_ucontext_t;
|
||||
#define TARGET_MCONTEXT_SIZE 640
|
||||
#define TARGET_UCONTEXT_SIZE 704
|
||||
|
||||
#include "target_os_ucontext.h"
|
||||
|
||||
struct target_sigframe {
|
||||
abi_ulong sf_signum;
|
||||
@ -53,40 +88,4 @@ struct target_sigframe {
|
||||
uint32_t __spare__[2];
|
||||
};
|
||||
|
||||
/*
|
||||
* Compare to i386/i386/machdep.c sendsig()
|
||||
* Assumes that target stack frame memory is locked.
|
||||
*/
|
||||
static inline abi_long set_sigtramp_args(CPUX86State *regs,
|
||||
int sig, struct target_sigframe *frame, abi_ulong frame_addr,
|
||||
struct target_sigaction *ka)
|
||||
{
|
||||
/* XXX return -TARGET_EOPNOTSUPP; */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compare to i386/i386/machdep.c get_mcontext() */
|
||||
static inline abi_long get_mcontext(CPUX86State *regs,
|
||||
target_mcontext_t *mcp, int flags)
|
||||
{
|
||||
/* XXX */
|
||||
return -TARGET_EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* Compare to i386/i386/machdep.c set_mcontext() */
|
||||
static inline abi_long set_mcontext(CPUX86State *regs,
|
||||
target_mcontext_t *mcp, int srflag)
|
||||
{
|
||||
/* XXX */
|
||||
return -TARGET_EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline abi_long get_ucontext_sigreturn(CPUX86State *regs,
|
||||
abi_ulong target_sf, abi_ulong *target_uc)
|
||||
{
|
||||
/* XXX */
|
||||
*target_uc = 0;
|
||||
return -TARGET_EOPNOTSUPP;
|
||||
}
|
||||
|
||||
#endif /* TARGET_ARCH_SIGNAL_H */
|
||||
|
@ -4,7 +4,7 @@ endif
|
||||
|
||||
bsd_user_ss = ss.source_set()
|
||||
|
||||
common_user_inc += include_directories('.')
|
||||
common_user_inc += include_directories('include')
|
||||
|
||||
bsd_user_ss.add(files(
|
||||
'bsdload.c',
|
||||
|
@ -1,69 +0,0 @@
|
||||
/*
|
||||
* mips sysarch() system call emulation
|
||||
*
|
||||
* Copyright (c) 2013 Stacey D. Son
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef BSD_USER_ARCH_SYSARCH_H_
|
||||
#define BSD_USER_ARCH_SYSARCH_H_
|
||||
|
||||
#include "target_syscall.h"
|
||||
#include "target_arch.h"
|
||||
|
||||
static inline abi_long do_freebsd_arch_sysarch(CPUMIPSState *env, int op,
|
||||
abi_ulong parms)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (op) {
|
||||
case TARGET_MIPS_SET_TLS:
|
||||
target_cpu_set_tls(env, parms);
|
||||
break;
|
||||
|
||||
case TARGET_MIPS_GET_TLS:
|
||||
if (put_user(target_cpu_get_tls(env), parms, abi_ulong)) {
|
||||
ret = -TARGET_EFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -TARGET_EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void do_freebsd_arch_print_sysarch(
|
||||
const struct syscallname *name, abi_long arg1, abi_long arg2,
|
||||
abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
|
||||
{
|
||||
|
||||
switch (arg1) {
|
||||
case TARGET_MIPS_SET_TLS:
|
||||
gemu_log("%s(SET_TLS, 0x" TARGET_ABI_FMT_lx ")", name->name, arg2);
|
||||
break;
|
||||
|
||||
case TARGET_MIPS_GET_TLS:
|
||||
gemu_log("%s(GET_TLS, 0x" TARGET_ABI_FMT_lx ")", name->name, arg2);
|
||||
break;
|
||||
|
||||
default:
|
||||
gemu_log("UNKNOWN OP: %d, " TARGET_ABI_FMT_lx ")", (int)arg1, arg2);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /*!BSD_USER_ARCH_SYSARCH_H_ */
|
@ -1,52 +0,0 @@
|
||||
/*
|
||||
* mips system call definitions
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef _MIPS_SYSCALL_H_
|
||||
#define _MIPS_SYSCALL_H_
|
||||
|
||||
/*
|
||||
* struct target_pt_regs defines the way the registers are stored on the stack
|
||||
* during a system call.
|
||||
*/
|
||||
|
||||
struct target_pt_regs {
|
||||
/* Saved main processor registers. */
|
||||
abi_ulong regs[32];
|
||||
|
||||
/* Saved special registers. */
|
||||
abi_ulong cp0_status;
|
||||
abi_ulong lo;
|
||||
abi_ulong hi;
|
||||
abi_ulong cp0_badvaddr;
|
||||
abi_ulong cp0_cause;
|
||||
abi_ulong cp0_epc;
|
||||
};
|
||||
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
#define UNAME_MACHINE "mips"
|
||||
#else
|
||||
#define UNAME_MACHINE "mipsel"
|
||||
#endif
|
||||
|
||||
#define TARGET_HW_MACHINE "mips"
|
||||
#define TARGET_HW_MACHINE_ARCH UNAME_MACHINE
|
||||
|
||||
/* sysarch() commands */
|
||||
#define TARGET_MIPS_SET_TLS 1
|
||||
#define TARGET_MIPS_GET_TLS 2
|
||||
|
||||
#endif /* !_MIPS_SYSCALL_H_ */
|
@ -1,69 +0,0 @@
|
||||
/*
|
||||
* mips64 sysarch() system call emulation
|
||||
*
|
||||
* Copyright (c) 2013 Stacey D. Son
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef BSD_USER_ARCH_SYSARCH_H_
|
||||
#define BSD_USER_ARCH_SYSARCH_H_
|
||||
|
||||
#include "target_syscall.h"
|
||||
#include "target_arch.h"
|
||||
|
||||
static inline abi_long do_freebsd_arch_sysarch(CPUMIPSState *env, int op,
|
||||
abi_ulong parms)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (op) {
|
||||
case TARGET_MIPS_SET_TLS:
|
||||
target_cpu_set_tls(env, parms);
|
||||
break;
|
||||
|
||||
case TARGET_MIPS_GET_TLS:
|
||||
if (put_user(target_cpu_get_tls(env), parms, abi_ulong)) {
|
||||
ret = -TARGET_EFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -TARGET_EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void do_freebsd_arch_print_sysarch(
|
||||
const struct syscallname *name, abi_long arg1, abi_long arg2,
|
||||
abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
|
||||
{
|
||||
|
||||
switch (arg1) {
|
||||
case TARGET_MIPS_SET_TLS:
|
||||
gemu_log("%s(SET_TLS, 0x" TARGET_ABI_FMT_lx ")", name->name, arg2);
|
||||
break;
|
||||
|
||||
case TARGET_MIPS_GET_TLS:
|
||||
gemu_log("%s(GET_TLS, 0x" TARGET_ABI_FMT_lx ")", name->name, arg2);
|
||||
break;
|
||||
|
||||
default:
|
||||
gemu_log("UNKNOWN OP: %d, " TARGET_ABI_FMT_lx ")", (int)arg1, arg2);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /*!BSD_USER_ARCH_SYSARCH_H_ */
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
* mips64 system call definitions
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef _MIPS64_SYSCALL_H_
|
||||
#define _MIPS64_SYSCALL_H_
|
||||
|
||||
/*
|
||||
* struct target_pt_regs defines the way the registers are stored on the stack
|
||||
* during a system call.
|
||||
*/
|
||||
|
||||
struct target_pt_regs {
|
||||
/* Saved main processor registers. */
|
||||
abi_ulong regs[32];
|
||||
|
||||
/* Saved special registers. */
|
||||
abi_ulong cp0_status;
|
||||
abi_ulong lo;
|
||||
abi_ulong hi;
|
||||
abi_ulong cp0_badvaddr;
|
||||
abi_ulong cp0_cause;
|
||||
abi_ulong cp0_epc;
|
||||
};
|
||||
|
||||
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
#define UNAME_MACHINE "mips64"
|
||||
#else
|
||||
#define UNAME_MACHINE "mips64el"
|
||||
#endif
|
||||
|
||||
#define TARGET_HW_MACHINE "mips"
|
||||
#define TARGET_HW_MACHINE_ARCH UNAME_MACHINE
|
||||
|
||||
/* sysarch() commands */
|
||||
#define TARGET_MIPS_SET_TLS 1
|
||||
#define TARGET_MIPS_GET_TLS 2
|
||||
|
||||
#endif /* !_MIPS64_SYSCALL_H_ */
|
55
bsd-user/x86_64/signal.c
Normal file
55
bsd-user/x86_64/signal.c
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* x86_64 signal definitions
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu.h"
|
||||
|
||||
/*
|
||||
* Compare to amd64/amd64/machdep.c sendsig()
|
||||
* Assumes that target stack frame memory is locked.
|
||||
*/
|
||||
abi_long set_sigtramp_args(CPUX86State *regs,
|
||||
int sig, struct target_sigframe *frame, abi_ulong frame_addr,
|
||||
struct target_sigaction *ka)
|
||||
{
|
||||
/* XXX return -TARGET_EOPNOTSUPP; */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compare to amd64/amd64/machdep.c get_mcontext() */
|
||||
abi_long get_mcontext(CPUX86State *regs,
|
||||
target_mcontext_t *mcp, int flags)
|
||||
{
|
||||
/* XXX */
|
||||
return -TARGET_EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* Compare to amd64/amd64/machdep.c set_mcontext() */
|
||||
abi_long set_mcontext(CPUX86State *regs,
|
||||
target_mcontext_t *mcp, int srflag)
|
||||
{
|
||||
/* XXX */
|
||||
return -TARGET_EOPNOTSUPP;
|
||||
}
|
||||
|
||||
abi_long get_ucontext_sigreturn(CPUX86State *regs,
|
||||
abi_ulong target_sf, abi_ulong *target_uc)
|
||||
{
|
||||
/* XXX */
|
||||
*target_uc = 0;
|
||||
return -TARGET_EOPNOTSUPP;
|
||||
}
|
@ -27,21 +27,64 @@
|
||||
#define TARGET_MINSIGSTKSZ (512 * 4) /* min sig stack size */
|
||||
#define TARGET_SIGSTKSZ (MINSIGSTKSZ + 32768) /* recommended size */
|
||||
|
||||
struct target_sigcontext {
|
||||
/* to be added */
|
||||
};
|
||||
|
||||
typedef struct target_mcontext {
|
||||
abi_ulong mc_onstack; /* XXX - sigcontext compat. */
|
||||
abi_ulong mc_rdi; /* machine state (struct trapframe) */
|
||||
abi_ulong mc_rsi;
|
||||
abi_ulong mc_rdx;
|
||||
abi_ulong mc_rcx;
|
||||
abi_ulong mc_r8;
|
||||
abi_ulong mc_r9;
|
||||
abi_ulong mc_rax;
|
||||
abi_ulong mc_rbx;
|
||||
abi_ulong mc_rbp;
|
||||
abi_ulong mc_r10;
|
||||
abi_ulong mc_r11;
|
||||
abi_ulong mc_r12;
|
||||
abi_ulong mc_r13;
|
||||
abi_ulong mc_r14;
|
||||
abi_ulong mc_r15;
|
||||
uint32_t mc_trapno;
|
||||
uint16_t mc_fs;
|
||||
uint16_t mc_gs;
|
||||
abi_ulong mc_addr;
|
||||
uint32_t mc_flags;
|
||||
uint16_t mc_es;
|
||||
uint16_t mc_ds;
|
||||
abi_ulong mc_err;
|
||||
abi_ulong mc_rip;
|
||||
abi_ulong mc_cs;
|
||||
abi_ulong mc_rflags;
|
||||
abi_ulong mc_rsp;
|
||||
abi_ulong mc_ss;
|
||||
|
||||
abi_long mc_len; /* sizeof(mcontext_t) */
|
||||
|
||||
#define _MC_FPFMT_NODEV 0x10000 /* device not present or configured */
|
||||
#define _MC_FPFMT_XMM 0x10002
|
||||
abi_long mc_fpformat;
|
||||
#define _MC_FPOWNED_NONE 0x20000 /* FP state not used */
|
||||
#define _MC_FPOWNED_FPU 0x20001 /* FP state came from FPU */
|
||||
#define _MC_FPOWNED_PCB 0x20002 /* FP state came from PCB */
|
||||
abi_long mc_ownedfp;
|
||||
/*
|
||||
* See <machine/fpu.h> for the internals of mc_fpstate[].
|
||||
*/
|
||||
abi_long mc_fpstate[64] __aligned(16);
|
||||
|
||||
abi_ulong mc_fsbase;
|
||||
abi_ulong mc_gsbase;
|
||||
|
||||
abi_ulong mc_xfpustate;
|
||||
abi_ulong mc_xfpustate_len;
|
||||
|
||||
abi_long mc_spare[4];
|
||||
} target_mcontext_t;
|
||||
|
||||
typedef struct target_ucontext {
|
||||
target_sigset_t uc_sigmask;
|
||||
target_mcontext_t uc_mcontext;
|
||||
abi_ulong uc_link;
|
||||
target_stack_t uc_stack;
|
||||
int32_t uc_flags;
|
||||
int32_t __spare__[4];
|
||||
} target_ucontext_t;
|
||||
#define TARGET_MCONTEXT_SIZE 800
|
||||
#define TARGET_UCONTEXT_SIZE 880
|
||||
|
||||
#include "target_os_ucontext.h"
|
||||
|
||||
struct target_sigframe {
|
||||
abi_ulong sf_signum;
|
||||
@ -53,40 +96,4 @@ struct target_sigframe {
|
||||
uint32_t __spare__[2];
|
||||
};
|
||||
|
||||
/*
|
||||
* Compare to amd64/amd64/machdep.c sendsig()
|
||||
* Assumes that target stack frame memory is locked.
|
||||
*/
|
||||
static inline abi_long set_sigtramp_args(CPUX86State *regs,
|
||||
int sig, struct target_sigframe *frame, abi_ulong frame_addr,
|
||||
struct target_sigaction *ka)
|
||||
{
|
||||
/* XXX return -TARGET_EOPNOTSUPP; */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compare to amd64/amd64/machdep.c get_mcontext() */
|
||||
static inline abi_long get_mcontext(CPUX86State *regs,
|
||||
target_mcontext_t *mcp, int flags)
|
||||
{
|
||||
/* XXX */
|
||||
return -TARGET_EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* Compare to amd64/amd64/machdep.c set_mcontext() */
|
||||
static inline abi_long set_mcontext(CPUX86State *regs,
|
||||
target_mcontext_t *mcp, int srflag)
|
||||
{
|
||||
/* XXX */
|
||||
return -TARGET_EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline abi_long get_ucontext_sigreturn(CPUX86State *regs,
|
||||
abi_ulong target_sf, abi_ulong *target_uc)
|
||||
{
|
||||
/* XXX */
|
||||
*target_uc = 0;
|
||||
return -TARGET_EOPNOTSUPP;
|
||||
}
|
||||
|
||||
#endif /* !TARGET_ARCH_SIGNAL_H_ */
|
||||
|
@ -25,9 +25,7 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "chardev/char.h"
|
||||
#include "io/channel-socket.h"
|
||||
#include "io/channel-tls.h"
|
||||
#include "io/channel-websock.h"
|
||||
#include "io/net-listener.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/option.h"
|
||||
@ -37,61 +35,7 @@
|
||||
#include "qemu/yank.h"
|
||||
|
||||
#include "chardev/char-io.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
/***********************************************************/
|
||||
/* TCP Net console */
|
||||
|
||||
#define TCP_MAX_FDS 16
|
||||
|
||||
typedef struct {
|
||||
char buf[21];
|
||||
size_t buflen;
|
||||
} TCPChardevTelnetInit;
|
||||
|
||||
typedef enum {
|
||||
TCP_CHARDEV_STATE_DISCONNECTED,
|
||||
TCP_CHARDEV_STATE_CONNECTING,
|
||||
TCP_CHARDEV_STATE_CONNECTED,
|
||||
} TCPChardevState;
|
||||
|
||||
struct SocketChardev {
|
||||
Chardev parent;
|
||||
QIOChannel *ioc; /* Client I/O channel */
|
||||
QIOChannelSocket *sioc; /* Client master channel */
|
||||
QIONetListener *listener;
|
||||
GSource *hup_source;
|
||||
QCryptoTLSCreds *tls_creds;
|
||||
char *tls_authz;
|
||||
TCPChardevState state;
|
||||
int max_size;
|
||||
int do_telnetopt;
|
||||
int do_nodelay;
|
||||
int *read_msgfds;
|
||||
size_t read_msgfds_num;
|
||||
int *write_msgfds;
|
||||
size_t write_msgfds_num;
|
||||
bool registered_yank;
|
||||
|
||||
SocketAddress *addr;
|
||||
bool is_listen;
|
||||
bool is_telnet;
|
||||
bool is_tn3270;
|
||||
GSource *telnet_source;
|
||||
TCPChardevTelnetInit *telnet_init;
|
||||
|
||||
bool is_websock;
|
||||
|
||||
GSource *reconnect_timer;
|
||||
int64_t reconnect_time;
|
||||
bool connect_err_reported;
|
||||
|
||||
QIOTask *connect_task;
|
||||
};
|
||||
typedef struct SocketChardev SocketChardev;
|
||||
|
||||
DECLARE_INSTANCE_CHECKER(SocketChardev, SOCKET_CHARDEV,
|
||||
TYPE_CHARDEV_SOCKET)
|
||||
#include "chardev/char-socket.h"
|
||||
|
||||
static gboolean socket_reconnect_timeout(gpointer opaque);
|
||||
static void tcp_chr_telnet_init(Chardev *chr);
|
||||
@ -346,13 +290,6 @@ static ssize_t tcp_chr_recv(Chardev *chr, char *buf, size_t len)
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (ret == QIO_CHANNEL_ERR_BLOCK) {
|
||||
errno = EAGAIN;
|
||||
ret = -1;
|
||||
} else if (ret == -1) {
|
||||
errno = EIO;
|
||||
}
|
||||
|
||||
if (msgfds_num) {
|
||||
/* close and clean read_msgfds */
|
||||
for (i = 0; i < s->read_msgfds_num; i++) {
|
||||
@ -381,6 +318,13 @@ static ssize_t tcp_chr_recv(Chardev *chr, char *buf, size_t len)
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ret == QIO_CHANNEL_ERR_BLOCK) {
|
||||
errno = EAGAIN;
|
||||
ret = -1;
|
||||
} else if (ret == -1) {
|
||||
errno = EIO;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -581,6 +525,7 @@ static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len)
|
||||
{
|
||||
SocketChardev *s = SOCKET_CHARDEV(chr);
|
||||
int size;
|
||||
int saved_errno;
|
||||
|
||||
if (s->state != TCP_CHARDEV_STATE_CONNECTED) {
|
||||
return 0;
|
||||
@ -588,6 +533,7 @@ static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len)
|
||||
|
||||
qio_channel_set_blocking(s->ioc, true, NULL);
|
||||
size = tcp_chr_recv(chr, (void *) buf, len);
|
||||
saved_errno = errno;
|
||||
if (s->state != TCP_CHARDEV_STATE_DISCONNECTED) {
|
||||
qio_channel_set_blocking(s->ioc, false, NULL);
|
||||
}
|
||||
@ -596,6 +542,7 @@ static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len)
|
||||
tcp_chr_disconnect(chr);
|
||||
}
|
||||
|
||||
errno = saved_errno;
|
||||
return size;
|
||||
}
|
||||
|
||||
@ -1248,6 +1195,10 @@ static int qmp_chardev_open_socket_server(Chardev *chr,
|
||||
qio_net_listener_set_name(s->listener, name);
|
||||
g_free(name);
|
||||
|
||||
if (s->addr->type == SOCKET_ADDRESS_TYPE_FD && !*s->addr->u.fd.str) {
|
||||
goto skip_listen;
|
||||
}
|
||||
|
||||
if (qio_net_listener_open_sync(s->listener, s->addr, 1, errp) < 0) {
|
||||
object_unref(OBJECT(s->listener));
|
||||
s->listener = NULL;
|
||||
@ -1256,6 +1207,8 @@ static int qmp_chardev_open_socket_server(Chardev *chr,
|
||||
|
||||
qapi_free_SocketAddress(s->addr);
|
||||
s->addr = socket_local_address(s->listener->sioc[0]->fd, errp);
|
||||
|
||||
skip_listen:
|
||||
update_disconnected_filename(s);
|
||||
|
||||
if (is_waitconnect) {
|
||||
@ -1466,9 +1419,9 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
|
||||
SocketAddressLegacy *addr;
|
||||
ChardevSocket *sock;
|
||||
|
||||
if ((!!path + !!fd + !!host) != 1) {
|
||||
if ((!!path + !!fd + !!host) > 1) {
|
||||
error_setg(errp,
|
||||
"Exactly one of 'path', 'fd' or 'host' required");
|
||||
"None or one of 'path', 'fd' or 'host' option required.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1542,12 +1495,10 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
|
||||
.has_ipv6 = qemu_opt_get(opts, "ipv6"),
|
||||
.ipv6 = qemu_opt_get_bool(opts, "ipv6", 0),
|
||||
};
|
||||
} else if (fd) {
|
||||
} else {
|
||||
addr->type = SOCKET_ADDRESS_TYPE_FD;
|
||||
addr->u.fd.data = g_new(String, 1);
|
||||
addr->u.fd.data->str = g_strdup(fd);
|
||||
} else {
|
||||
g_assert_not_reached();
|
||||
}
|
||||
sock->addr = addr;
|
||||
}
|
||||
|
@ -120,6 +120,7 @@ safe_syscall_end:
|
||||
pop %ebp
|
||||
.cfi_adjust_cfa_offset -4
|
||||
.cfi_restore ebp
|
||||
mov %eax, 4(%esp)
|
||||
jmp safe_syscall_set_errno_tail
|
||||
|
||||
.cfi_endproc
|
||||
|
90
common-user/host/loongarch64/safe-syscall.inc.S
Normal file
90
common-user/host/loongarch64/safe-syscall.inc.S
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* safe-syscall.inc.S : host-specific assembly fragment
|
||||
* to handle signals occurring at the same time as system calls.
|
||||
* This is intended to be included by common-user/safe-syscall.S
|
||||
*
|
||||
* Ported to LoongArch by WANG Xuerui <git@xen0n.name>
|
||||
*
|
||||
* Based on safe-syscall.inc.S code for RISC-V,
|
||||
* originally written by Richard Henderson <rth@twiddle.net>
|
||||
* Copyright (C) 2018 Linaro, Inc.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
.global safe_syscall_base
|
||||
.global safe_syscall_start
|
||||
.global safe_syscall_end
|
||||
.type safe_syscall_base, @function
|
||||
.type safe_syscall_start, @function
|
||||
.type safe_syscall_end, @function
|
||||
|
||||
/*
|
||||
* This is the entry point for making a system call. The calling
|
||||
* convention here is that of a C varargs function with the
|
||||
* first argument an 'int *' to the signal_pending flag, the
|
||||
* second one the system call number (as a 'long'), and all further
|
||||
* arguments being syscall arguments (also 'long').
|
||||
*/
|
||||
safe_syscall_base:
|
||||
.cfi_startproc
|
||||
/*
|
||||
* The syscall calling convention is nearly the same as C:
|
||||
* we enter with a0 == &signal_pending
|
||||
* a1 == syscall number
|
||||
* a2 ... a7 == syscall arguments
|
||||
* and return the result in a0
|
||||
* and the syscall instruction needs
|
||||
* a7 == syscall number
|
||||
* a0 ... a5 == syscall arguments
|
||||
* and returns the result in a0
|
||||
* Shuffle everything around appropriately.
|
||||
*/
|
||||
move $t0, $a0 /* signal_pending pointer */
|
||||
move $t1, $a1 /* syscall number */
|
||||
move $a0, $a2 /* syscall arguments */
|
||||
move $a1, $a3
|
||||
move $a2, $a4
|
||||
move $a3, $a5
|
||||
move $a4, $a6
|
||||
move $a5, $a7
|
||||
move $a7, $t1
|
||||
|
||||
/*
|
||||
* We need to preserve the signal_pending pointer but t0 is
|
||||
* clobbered by syscalls on LoongArch, so we need to move it
|
||||
* somewhere else, ideally both preserved across syscalls and
|
||||
* clobbered by procedure calls so we don't have to allocate a
|
||||
* stack frame; a6 is just the register we want here.
|
||||
*/
|
||||
move $a6, $t0
|
||||
|
||||
/*
|
||||
* This next sequence of code works in conjunction with the
|
||||
* rewind_if_safe_syscall_function(). If a signal is taken
|
||||
* and the interrupted PC is anywhere between 'safe_syscall_start'
|
||||
* and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
|
||||
* The code sequence must therefore be able to cope with this, and
|
||||
* the syscall instruction must be the final one in the sequence.
|
||||
*/
|
||||
safe_syscall_start:
|
||||
/* If signal_pending is non-zero, don't do the call */
|
||||
ld.w $t1, $a6, 0
|
||||
bnez $t1, 2f
|
||||
syscall 0
|
||||
safe_syscall_end:
|
||||
/* code path for having successfully executed the syscall */
|
||||
li.w $t2, -4096
|
||||
bgtu $a0, $t2, 0f
|
||||
jr $ra
|
||||
|
||||
/* code path setting errno */
|
||||
0: sub.d $a0, $zero, $a0
|
||||
b safe_syscall_set_errno_tail
|
||||
|
||||
/* code path when we didn't execute the syscall */
|
||||
2: li.w $a0, QEMU_ERESTARTSYS
|
||||
b safe_syscall_set_errno_tail
|
||||
.cfi_endproc
|
||||
.size safe_syscall_base, .-safe_syscall_base
|
@ -141,6 +141,7 @@ safe_syscall_end:
|
||||
1: USE_ALT_CP(t0)
|
||||
SETUP_GPX(t1)
|
||||
SETUP_GPX64(t0, t1)
|
||||
move a0, v0
|
||||
PTR_LA t9, safe_syscall_set_errno_tail
|
||||
jr t9
|
||||
|
||||
|
@ -99,6 +99,7 @@ safe_syscall_end:
|
||||
1: pop %rbp
|
||||
.cfi_def_cfa_offset 8
|
||||
.cfi_restore rbp
|
||||
mov %eax, %edi
|
||||
jmp safe_syscall_set_errno_tail
|
||||
.cfi_endproc
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
common_user_inc += include_directories('host/' / host_arch)
|
||||
|
||||
common_user_ss.add(files(
|
||||
user_ss.add(files(
|
||||
'safe-syscall.S',
|
||||
'safe-syscall-error.c',
|
||||
))
|
||||
|
@ -7,7 +7,7 @@ CONFIG_ISA_BUS=y
|
||||
CONFIG_PCI=y
|
||||
CONFIG_PCI_DEVICES=y
|
||||
CONFIG_VGA_ISA=y
|
||||
CONFIG_VGA_ISA_MM=y
|
||||
CONFIG_VGA_MMIO=y
|
||||
CONFIG_VGA_CIRRUS=y
|
||||
CONFIG_VMWARE_VGA=y
|
||||
CONFIG_SERIAL=y
|
||||
|
2
configs/targets/arm-bsd-user.mak
Normal file
2
configs/targets/arm-bsd-user.mak
Normal file
@ -0,0 +1,2 @@
|
||||
TARGET_ARCH=arm
|
||||
TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml gdb-xml/arm-m-profile-mve.xml
|
193
configure
vendored
193
configure
vendored
@ -78,7 +78,6 @@ TMPC="${TMPDIR1}/${TMPB}.c"
|
||||
TMPO="${TMPDIR1}/${TMPB}.o"
|
||||
TMPCXX="${TMPDIR1}/${TMPB}.cxx"
|
||||
TMPE="${TMPDIR1}/${TMPB}.exe"
|
||||
TMPTXT="${TMPDIR1}/${TMPB}.txt"
|
||||
|
||||
rm -f config.log
|
||||
|
||||
@ -291,7 +290,6 @@ EXTRA_CXXFLAGS=""
|
||||
EXTRA_LDFLAGS=""
|
||||
|
||||
xen_ctrl_version="$default_feature"
|
||||
xfs="$default_feature"
|
||||
membarrier="$default_feature"
|
||||
vhost_kernel="$default_feature"
|
||||
vhost_net="$default_feature"
|
||||
@ -309,21 +307,16 @@ debug="no"
|
||||
sanitizers="no"
|
||||
tsan="no"
|
||||
fortify_source="$default_feature"
|
||||
strip_opt="yes"
|
||||
mingw32="no"
|
||||
gcov="no"
|
||||
EXESUF=""
|
||||
modules="no"
|
||||
module_upgrades="no"
|
||||
prefix="/usr/local"
|
||||
qemu_suffix="qemu"
|
||||
bsd="no"
|
||||
linux="no"
|
||||
solaris="no"
|
||||
profiler="no"
|
||||
softmmu="yes"
|
||||
linux_user="no"
|
||||
bsd_user="no"
|
||||
linux_user=""
|
||||
bsd_user=""
|
||||
pkgversion=""
|
||||
pie=""
|
||||
qom_cast_debug="yes"
|
||||
@ -333,8 +326,6 @@ opengl="$default_feature"
|
||||
cpuid_h="no"
|
||||
avx2_opt="$default_feature"
|
||||
guest_agent="$default_feature"
|
||||
guest_agent_with_vss="no"
|
||||
guest_agent_ntddscsi="no"
|
||||
vss_win32_sdk="$default_feature"
|
||||
win_sdk="no"
|
||||
want_tools="$default_feature"
|
||||
@ -529,6 +520,10 @@ fi
|
||||
|
||||
# OS specific
|
||||
|
||||
mingw32="no"
|
||||
bsd="no"
|
||||
linux="no"
|
||||
solaris="no"
|
||||
case $targetos in
|
||||
windows)
|
||||
mingw32="yes"
|
||||
@ -540,7 +535,6 @@ gnu/kfreebsd)
|
||||
;;
|
||||
freebsd)
|
||||
bsd="yes"
|
||||
bsd_user="yes"
|
||||
make="${MAKE-gmake}"
|
||||
# needed for kinfo_getvmmap(3) in libutil.h
|
||||
;;
|
||||
@ -585,7 +579,6 @@ haiku)
|
||||
;;
|
||||
linux)
|
||||
linux="yes"
|
||||
linux_user="yes"
|
||||
vhost_user=${default_feature:-yes}
|
||||
;;
|
||||
esac
|
||||
@ -631,6 +624,8 @@ elif check_define __arm__ ; then
|
||||
cpu="arm"
|
||||
elif check_define __aarch64__ ; then
|
||||
cpu="aarch64"
|
||||
elif check_define __loongarch64 ; then
|
||||
cpu="loongarch64"
|
||||
else
|
||||
cpu=$(uname -m)
|
||||
fi
|
||||
@ -896,7 +891,6 @@ for opt do
|
||||
debug_tcg="yes"
|
||||
debug_mutex="yes"
|
||||
debug="yes"
|
||||
strip_opt="no"
|
||||
fortify_source="no"
|
||||
;;
|
||||
--enable-sanitizers) sanitizers="yes"
|
||||
@ -907,8 +901,6 @@ for opt do
|
||||
;;
|
||||
--disable-tsan) tsan="no"
|
||||
;;
|
||||
--disable-strip) strip_opt="no"
|
||||
;;
|
||||
--disable-slirp) slirp="disabled"
|
||||
;;
|
||||
--enable-slirp) slirp="enabled"
|
||||
@ -1021,10 +1013,6 @@ for opt do
|
||||
;;
|
||||
--enable-opengl) opengl="yes"
|
||||
;;
|
||||
--disable-xfsctl) xfs="no"
|
||||
;;
|
||||
--enable-xfsctl) xfs="yes"
|
||||
;;
|
||||
--disable-zlib-test)
|
||||
;;
|
||||
--enable-guest-agent) guest_agent="yes"
|
||||
@ -1275,18 +1263,26 @@ if eval test -z "\${cross_cc_$cpu}"; then
|
||||
cross_cc_vars="$cross_cc_vars cross_cc_${cpu}"
|
||||
fi
|
||||
|
||||
# For user-mode emulation the host arch has to be one we explicitly
|
||||
# support, even if we're using TCI.
|
||||
if [ "$ARCH" = "unknown" ]; then
|
||||
bsd_user="no"
|
||||
linux_user="no"
|
||||
fi
|
||||
|
||||
default_target_list=""
|
||||
deprecated_targets_list=ppc64abi32-linux-user
|
||||
deprecated_features=""
|
||||
mak_wilds=""
|
||||
|
||||
if [ "$linux_user" != no ]; then
|
||||
if [ "$targetos" = linux ] && [ -d $source_path/linux-user/include/host/$cpu ]; then
|
||||
linux_user=yes
|
||||
elif [ "$linux_user" = yes ]; then
|
||||
error_exit "linux-user not supported on this architecture"
|
||||
fi
|
||||
fi
|
||||
if [ "$bsd_user" != no ]; then
|
||||
if [ "$bsd_user" = "" ]; then
|
||||
test $targetos = freebsd && bsd_user=yes
|
||||
fi
|
||||
if [ "$bsd_user" = yes ] && ! [ -d $source_path/bsd-user/$targetos ]; then
|
||||
error_exit "bsd-user not supported on this host OS"
|
||||
fi
|
||||
fi
|
||||
if [ "$softmmu" = "yes" ]; then
|
||||
mak_wilds="${mak_wilds} $source_path/configs/targets/*-softmmu.mak"
|
||||
fi
|
||||
@ -1377,7 +1373,6 @@ Advanced options (experts only):
|
||||
--enable-debug enable common debug build options
|
||||
--enable-sanitizers enable default sanitizers
|
||||
--enable-tsan enable thread sanitizer
|
||||
--disable-strip disable stripping binaries
|
||||
--disable-werror disable compilation abort on warning
|
||||
--disable-stack-protector disable compiler-provided stack protection
|
||||
--audio-drv-list=LIST set audio drivers to try if -audiodev is not used
|
||||
@ -1441,7 +1436,6 @@ cat << EOF
|
||||
avx512f AVX512F optimization support
|
||||
replication replication support
|
||||
opengl opengl support
|
||||
xfsctl xfsctl support
|
||||
qom-cast-debug cast debugging support
|
||||
tools build qemu-io, qemu-nbd and qemu-img tools
|
||||
bochs bochs image format support
|
||||
@ -1712,6 +1706,7 @@ if test "$static" = "yes" ; then
|
||||
plugins="no"
|
||||
fi
|
||||
fi
|
||||
test "$plugins" = "" && plugins=yes
|
||||
|
||||
cat > $TMPC << EOF
|
||||
|
||||
@ -2333,91 +2328,6 @@ EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# xfsctl() probe, used for file-posix.c
|
||||
if test "$xfs" != "no" ; then
|
||||
cat > $TMPC << EOF
|
||||
#include <stddef.h> /* NULL */
|
||||
#include <xfs/xfs.h>
|
||||
int main(void)
|
||||
{
|
||||
xfsctl(NULL, 0, 0, NULL);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if compile_prog "" "" ; then
|
||||
xfs="yes"
|
||||
else
|
||||
if test "$xfs" = "yes" ; then
|
||||
feature_not_found "xfs" "Install xfsprogs/xfslibs devel"
|
||||
fi
|
||||
xfs=no
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# plugin linker support probe
|
||||
|
||||
if test "$plugins" != "no"; then
|
||||
|
||||
#########################################
|
||||
# See if --dynamic-list is supported by the linker
|
||||
|
||||
ld_dynamic_list="no"
|
||||
cat > $TMPTXT <<EOF
|
||||
{
|
||||
foo;
|
||||
};
|
||||
EOF
|
||||
|
||||
cat > $TMPC <<EOF
|
||||
#include <stdio.h>
|
||||
void foo(void);
|
||||
|
||||
void foo(void)
|
||||
{
|
||||
printf("foo\n");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
foo();
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
|
||||
if compile_prog "" "-Wl,--dynamic-list=$TMPTXT" ; then
|
||||
ld_dynamic_list="yes"
|
||||
fi
|
||||
|
||||
#########################################
|
||||
# See if -exported_symbols_list is supported by the linker
|
||||
|
||||
ld_exported_symbols_list="no"
|
||||
cat > $TMPTXT <<EOF
|
||||
_foo
|
||||
EOF
|
||||
|
||||
if compile_prog "" "-Wl,-exported_symbols_list,$TMPTXT" ; then
|
||||
ld_exported_symbols_list="yes"
|
||||
fi
|
||||
|
||||
if test "$ld_dynamic_list" = "no" &&
|
||||
test "$ld_exported_symbols_list" = "no" ; then
|
||||
if test "$plugins" = "yes"; then
|
||||
error_exit \
|
||||
"Plugin support requires dynamic linking and specifying a set of symbols " \
|
||||
"that are exported to plugins. Unfortunately your linker doesn't " \
|
||||
"support the flag (--dynamic-list or -exported_symbols_list) used " \
|
||||
"for this purpose."
|
||||
else
|
||||
plugins="no"
|
||||
fi
|
||||
else
|
||||
plugins="yes"
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# glib support probe
|
||||
|
||||
@ -2649,6 +2559,7 @@ fi
|
||||
##########################################
|
||||
# check if we have VSS SDK headers for win
|
||||
|
||||
guest_agent_with_vss="no"
|
||||
if test "$mingw32" = "yes" && test "$guest_agent" != "no" && \
|
||||
test "$vss_win32_sdk" != "no" ; then
|
||||
case "$vss_win32_sdk" in
|
||||
@ -2679,7 +2590,6 @@ EOF
|
||||
echo "ERROR: The headers are extracted in the directory \`inc'."
|
||||
feature_not_found "VSS support"
|
||||
fi
|
||||
guest_agent_with_vss="no"
|
||||
fi
|
||||
fi
|
||||
|
||||
@ -2706,6 +2616,7 @@ fi
|
||||
|
||||
##########################################
|
||||
# check if mingw environment provides a recent ntddscsi.h
|
||||
guest_agent_ntddscsi="no"
|
||||
if test "$mingw32" = "yes" && test "$guest_agent" != "no"; then
|
||||
cat > $TMPC << EOF
|
||||
#include <windows.h>
|
||||
@ -3410,9 +3321,6 @@ echo "GIT_SUBMODULES_ACTION=$git_submodules_action" >> $config_host_mak
|
||||
if test "$debug_tcg" = "yes" ; then
|
||||
echo "CONFIG_DEBUG_TCG=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$strip_opt" = "yes" ; then
|
||||
echo "STRIP=${strip}" >> $config_host_mak
|
||||
fi
|
||||
if test "$mingw32" = "yes" ; then
|
||||
echo "CONFIG_WIN32=y" >> $config_host_mak
|
||||
if test "$guest_agent_with_vss" = "yes" ; then
|
||||
@ -3466,9 +3374,6 @@ echo "CONFIG_BDRV_RO_WHITELIST=$block_drv_ro_whitelist" >> $config_host_mak
|
||||
if test "$block_drv_whitelist_tools" = "yes" ; then
|
||||
echo "CONFIG_BDRV_WHITELIST_TOOLS=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$xfs" = "yes" ; then
|
||||
echo "CONFIG_XFS=y" >> $config_host_mak
|
||||
fi
|
||||
qemu_version=$(head $source_path/VERSION)
|
||||
echo "PKGVERSION=$pkgversion" >>$config_host_mak
|
||||
echo "SRC_PATH=$source_path" >> $config_host_mak
|
||||
@ -3655,22 +3560,6 @@ fi
|
||||
|
||||
if test "$plugins" = "yes" ; then
|
||||
echo "CONFIG_PLUGIN=y" >> $config_host_mak
|
||||
# Copy the export object list to the build dir
|
||||
if test "$ld_dynamic_list" = "yes" ; then
|
||||
echo "CONFIG_HAS_LD_DYNAMIC_LIST=yes" >> $config_host_mak
|
||||
ld_symbols=qemu-plugins-ld.symbols
|
||||
cp "$source_path/plugins/qemu-plugins.symbols" $ld_symbols
|
||||
elif test "$ld_exported_symbols_list" = "yes" ; then
|
||||
echo "CONFIG_HAS_LD_EXPORTED_SYMBOLS_LIST=yes" >> $config_host_mak
|
||||
ld64_symbols=qemu-plugins-ld64.symbols
|
||||
echo "# Automatically generated by configure - do not modify" > $ld64_symbols
|
||||
grep 'qemu_' "$source_path/plugins/qemu-plugins.symbols" | sed 's/;//g' | \
|
||||
sed -E 's/^[[:space:]]*(.*)/_\1/' >> $ld64_symbols
|
||||
else
|
||||
error_exit \
|
||||
"If \$plugins=yes, either \$ld_dynamic_list or " \
|
||||
"\$ld_exported_symbols_list should have been set to 'yes'."
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$gdb_bin"; then
|
||||
@ -3713,8 +3602,10 @@ echo "QEMU_CFLAGS=$QEMU_CFLAGS" >> $config_host_mak
|
||||
echo "QEMU_CXXFLAGS=$QEMU_CXXFLAGS" >> $config_host_mak
|
||||
echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
|
||||
echo "GLIB_LIBS=$glib_libs" >> $config_host_mak
|
||||
echo "GLIB_VERSION=$(pkg-config --modversion glib-2.0)" >> $config_host_mak
|
||||
echo "QEMU_LDFLAGS=$QEMU_LDFLAGS" >> $config_host_mak
|
||||
echo "LD_I386_EMULATION=$ld_i386_emulation" >> $config_host_mak
|
||||
echo "STRIP=$strip" >> $config_host_mak
|
||||
echo "EXESUF=$EXESUF" >> $config_host_mak
|
||||
echo "LIBS_QGA=$libs_qga" >> $config_host_mak
|
||||
|
||||
@ -3738,6 +3629,9 @@ if test "$linux" = "yes" ; then
|
||||
aarch64)
|
||||
linux_arch=arm64
|
||||
;;
|
||||
loongarch*)
|
||||
linux_arch=loongarch
|
||||
;;
|
||||
mips64)
|
||||
linux_arch=mips
|
||||
;;
|
||||
@ -3789,9 +3683,6 @@ fi
|
||||
# so the build tree will be missing the link back to the new file, and
|
||||
# tests might fail. Prefer to keep the relevant files in their own
|
||||
# directory and symlink the directory instead.
|
||||
# UNLINK is used to remove symlinks from older development versions
|
||||
# that might get into the way when doing "git update" without doing
|
||||
# a "make distclean" in between.
|
||||
LINKS="Makefile"
|
||||
LINKS="$LINKS tests/tcg/Makefile.target"
|
||||
LINKS="$LINKS pc-bios/optionrom/Makefile"
|
||||
@ -3803,7 +3694,6 @@ LINKS="$LINKS tests/avocado tests/data"
|
||||
LINKS="$LINKS tests/qemu-iotests/check"
|
||||
LINKS="$LINKS python"
|
||||
LINKS="$LINKS contrib/plugins/Makefile "
|
||||
UNLINK="pc-bios/keymaps"
|
||||
for bios_file in \
|
||||
$source_path/pc-bios/*.bin \
|
||||
$source_path/pc-bios/*.elf \
|
||||
@ -3825,19 +3715,15 @@ for f in $LINKS ; do
|
||||
symlink "$source_path/$f" "$f"
|
||||
fi
|
||||
done
|
||||
for f in $UNLINK ; do
|
||||
if [ -L "$f" ]; then
|
||||
rm -f "$f"
|
||||
fi
|
||||
done
|
||||
|
||||
(for i in $cross_cc_vars; do
|
||||
export $i
|
||||
done
|
||||
export target_list source_path use_containers ARCH
|
||||
export target_list source_path use_containers cpu
|
||||
$source_path/tests/tcg/configure.sh)
|
||||
|
||||
# temporary config to build submodules
|
||||
if test -f $source_path/roms/seabios/Makefile; then
|
||||
for rom in seabios; do
|
||||
config_mak=roms/$rom/config.mak
|
||||
echo "# Automatically generated by configure - do not modify" > $config_mak
|
||||
@ -3852,6 +3738,7 @@ for rom in seabios; do
|
||||
echo "LD=$ld" >> $config_mak
|
||||
echo "RANLIB=$ranlib" >> $config_mak
|
||||
done
|
||||
fi
|
||||
|
||||
config_mak=pc-bios/optionrom/config.mak
|
||||
echo "# Automatically generated by configure - do not modify" > $config_mak
|
||||
@ -3938,7 +3825,6 @@ if test "$skip_meson" = no; then
|
||||
-Doptimization=$(if test "$debug" = yes; then echo 0; else echo 2; fi) \
|
||||
-Ddebug=$(if test "$debug_info" = yes; then echo true; else echo false; fi) \
|
||||
-Dwerror=$(if test "$werror" = yes; then echo true; else echo false; fi) \
|
||||
-Dstrip=$(if test "$strip_opt" = yes; then echo true; else echo false; fi) \
|
||||
-Db_pie=$(if test "$pie" = yes; then echo true; else echo false; fi) \
|
||||
-Db_coverage=$(if test "$gcov" = yes; then echo true; else echo false; fi) \
|
||||
-Db_lto=$lto -Dcfi=$cfi -Dtcg=$tcg -Dxen=$xen \
|
||||
@ -3969,17 +3855,6 @@ if test -n "${deprecated_features}"; then
|
||||
echo " features: ${deprecated_features}"
|
||||
fi
|
||||
|
||||
# Create list of config switches that should be poisoned in common code...
|
||||
# but filter out CONFIG_TCG and CONFIG_USER_ONLY which are special.
|
||||
target_configs_h=$(ls *-config-devices.h *-config-target.h 2>/dev/null)
|
||||
if test -n "$target_configs_h" ; then
|
||||
sed -n -e '/CONFIG_TCG/d' -e '/CONFIG_USER_ONLY/d' \
|
||||
-e '/^#define / { s///; s/ .*//; s/^/#pragma GCC poison /p; }' \
|
||||
$target_configs_h | sort -u > config-poison.h
|
||||
else
|
||||
:> config-poison.h
|
||||
fi
|
||||
|
||||
# Save the configure command line for later reuse.
|
||||
cat <<EOD >config.status
|
||||
#!/bin/sh
|
||||
|
@ -1,5 +1,5 @@
|
||||
if curl.found()
|
||||
executable('elf2dmp', files('main.c', 'addrspace.c', 'download.c', 'pdb.c', 'qemu_elf.c'),
|
||||
executable('elf2dmp', files('main.c', 'addrspace.c', 'download.c', 'pdb.c', 'qemu_elf.c'), genh,
|
||||
dependencies: [glib, curl],
|
||||
install: true)
|
||||
endif
|
||||
|
@ -1,4 +1,4 @@
|
||||
executable('ivshmem-client', files('ivshmem-client.c', 'main.c'),
|
||||
executable('ivshmem-client', files('ivshmem-client.c', 'main.c'), genh,
|
||||
dependencies: glib,
|
||||
build_by_default: targetos == 'linux',
|
||||
install: false)
|
||||
|
@ -1,4 +1,4 @@
|
||||
executable('ivshmem-server', files('ivshmem-server.c', 'main.c'),
|
||||
executable('ivshmem-server', files('ivshmem-server.c', 'main.c'), genh,
|
||||
dependencies: [qemuutil, rt],
|
||||
build_by_default: targetos == 'linux',
|
||||
install: false)
|
||||
|
@ -2,7 +2,7 @@ if 'CONFIG_PVRDMA' in config_host
|
||||
# if not found, CONFIG_PVRDMA should not be set
|
||||
# FIXME: broken on big endian architectures
|
||||
libumad = cc.find_library('ibumad', required: true)
|
||||
executable('rdmacm-mux', files('main.c'),
|
||||
executable('rdmacm-mux', files('main.c'), genh,
|
||||
dependencies: [glib, libumad],
|
||||
build_by_default: false,
|
||||
install: false)
|
||||
|
22
cpu.c
22
cpu.c
@ -355,13 +355,23 @@ void cpu_exec_unrealizefn(CPUState *cpu)
|
||||
cpu_list_remove(cpu);
|
||||
}
|
||||
|
||||
static Property cpu_common_props[] = {
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
/*
|
||||
* Create a memory property for softmmu CPU object,
|
||||
* so users can wire up its memory. (This can't go in hw/core/cpu.c
|
||||
* because that file is compiled only once for both user-mode
|
||||
* and system builds.) The default if no link is set up is to use
|
||||
* This can't go in hw/core/cpu.c because that file is compiled only
|
||||
* once for both user-mode and system builds.
|
||||
*/
|
||||
static Property cpu_common_props[] = {
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/*
|
||||
* Create a property for the user-only object, so users can
|
||||
* adjust prctl(PR_SET_UNALIGN) from the command-line.
|
||||
* Has no effect if the target does not support the feature.
|
||||
*/
|
||||
DEFINE_PROP_BOOL("prctl-unalign-sigbus", CPUState,
|
||||
prctl_unalign_sigbus, false),
|
||||
#else
|
||||
/*
|
||||
* Create a memory property for softmmu CPU object, so users can
|
||||
* wire up its memory. The default if no link is set up is to use
|
||||
* the system address space.
|
||||
*/
|
||||
DEFINE_PROP_LINK("memory", CPUState, memory, TYPE_MEMORY_REGION,
|
||||
|
@ -3090,3 +3090,8 @@ int print_insn_riscv64(bfd_vma memaddr, struct disassemble_info *info)
|
||||
{
|
||||
return print_insn_riscv(memaddr, info, rv64);
|
||||
}
|
||||
|
||||
int print_insn_riscv128(bfd_vma memaddr, struct disassemble_info *info)
|
||||
{
|
||||
return print_insn_riscv(memaddr, info, rv128);
|
||||
}
|
||||
|
@ -134,12 +134,6 @@ specified.
|
||||
Use ``-display sdl,window-close=...`` instead (i.e. with a minus instead of
|
||||
an underscore between "window" and "close").
|
||||
|
||||
``-no-quit`` (since 6.1)
|
||||
''''''''''''''''''''''''
|
||||
|
||||
The ``-no-quit`` is a synonym for ``-display ...,window-close=off`` which
|
||||
should be used instead.
|
||||
|
||||
``-alt-grab`` and ``-display sdl,alt_grab=on`` (since 6.2)
|
||||
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
|
@ -330,6 +330,13 @@ RISC-V firmware not booted by default (removed in 5.1)
|
||||
QEMU 5.1 changes the default behaviour from ``-bios none`` to ``-bios default``
|
||||
for the RISC-V ``virt`` machine and ``sifive_u`` machine.
|
||||
|
||||
``-no-quit`` (removed in 7.0)
|
||||
'''''''''''''''''''''''''''''
|
||||
|
||||
The ``-no-quit`` was a synonym for ``-display ...,window-close=off`` which
|
||||
should be used instead.
|
||||
|
||||
|
||||
QEMU Machine Protocol (QMP) commands
|
||||
------------------------------------
|
||||
|
||||
|
@ -73,6 +73,12 @@ needs_sphinx = '1.6'
|
||||
# ones.
|
||||
extensions = ['kerneldoc', 'qmp_lexer', 'hxtool', 'depfile', 'qapidoc']
|
||||
|
||||
if sphinx.version_info[:3] > (4, 0, 0):
|
||||
tags.add('sphinx4')
|
||||
extensions += ['dbusdoc']
|
||||
else:
|
||||
extensions += ['fakedbusdoc']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = [os.path.join(qemu_docdir, '_templates')]
|
||||
|
||||
@ -311,3 +317,5 @@ kerneldoc_bin = ['perl', os.path.join(qemu_docdir, '../scripts/kernel-doc')]
|
||||
kerneldoc_srctree = os.path.join(qemu_docdir, '..')
|
||||
hxtool_srctree = os.path.join(qemu_docdir, '..')
|
||||
qapidoc_srctree = os.path.join(qemu_docdir, '..')
|
||||
dbusdoc_srctree = os.path.join(qemu_docdir, '..')
|
||||
dbus_index_common_prefix = ["org.qemu."]
|
||||
|
@ -68,10 +68,14 @@ MemoryRegion):
|
||||
You initialize a pure container with memory_region_init().
|
||||
|
||||
- alias: a subsection of another region. Aliases allow a region to be
|
||||
split apart into discontiguous regions. Examples of uses are memory banks
|
||||
used when the guest address space is smaller than the amount of RAM
|
||||
addressed, or a memory controller that splits main memory to expose a "PCI
|
||||
hole". Aliases may point to any type of region, including other aliases,
|
||||
split apart into discontiguous regions. Examples of uses are memory
|
||||
banks used when the guest address space is smaller than the amount
|
||||
of RAM addressed, or a memory controller that splits main memory to
|
||||
expose a "PCI hole". You can also create aliases to avoid trying to
|
||||
add the original region to multiple parents via
|
||||
`memory_region_add_subregion`.
|
||||
|
||||
Aliases may point to any type of region, including other aliases,
|
||||
but an alias may not point back to itself, directly or indirectly.
|
||||
You initialize these with memory_region_init_alias().
|
||||
|
||||
|
@ -151,6 +151,12 @@ If there are two versions of a function to be called with or without a
|
||||
lock held, the function that expects the lock to be already held
|
||||
usually uses the suffix ``_locked``.
|
||||
|
||||
If a function is a shim designed to deal with compatibility
|
||||
workarounds we use the suffix ``_compat``. These are generally not
|
||||
called directly and aliased to the plain function name via the
|
||||
pre-processor. Another common suffix is ``_impl``; it is used for the
|
||||
concrete implementation of a function that will not be called
|
||||
directly, but rather through a macro or an inline function.
|
||||
|
||||
Block structure
|
||||
===============
|
||||
@ -483,11 +489,11 @@ of arguments.
|
||||
C standard, implementation defined and undefined behaviors
|
||||
==========================================================
|
||||
|
||||
C code in QEMU should be written to the C99 language specification. A copy
|
||||
of the final version of the C99 standard with corrigenda TC1, TC2, and TC3
|
||||
included, formatted as a draft, can be downloaded from:
|
||||
C code in QEMU should be written to the C11 language specification. A
|
||||
copy of the final version of the C11 standard formatted as a draft,
|
||||
can be downloaded from:
|
||||
|
||||
`<http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf>`_
|
||||
`<http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1548.pdf>`_
|
||||
|
||||
The C language specification defines regions of undefined behavior and
|
||||
implementation defined behavior (to give compiler authors enough leeway to
|
||||
|
@ -382,14 +382,112 @@ Along with many other images, the ``centos8`` image is defined in a Dockerfile
|
||||
in ``tests/docker/dockerfiles/``, called ``centos8.docker``. ``make docker-help``
|
||||
command will list all the available images.
|
||||
|
||||
To add a new image, simply create a new ``.docker`` file under the
|
||||
``tests/docker/dockerfiles/`` directory.
|
||||
|
||||
A ``.pre`` script can be added beside the ``.docker`` file, which will be
|
||||
executed before building the image under the build context directory. This is
|
||||
mainly used to do necessary host side setup. One such setup is ``binfmt_misc``,
|
||||
for example, to make qemu-user powered cross build containers work.
|
||||
|
||||
Most of the existing Dockerfiles were written by hand, simply by creating a
|
||||
a new ``.docker`` file under the ``tests/docker/dockerfiles/`` directory.
|
||||
This has led to an inconsistent set of packages being present across the
|
||||
different containers.
|
||||
|
||||
Thus going forward, QEMU is aiming to automatically generate the Dockerfiles
|
||||
using the ``lcitool`` program provided by the ``libvirt-ci`` project:
|
||||
|
||||
https://gitlab.com/libvirt/libvirt-ci
|
||||
|
||||
In that project, there is a ``mappings.yml`` file defining the distro native
|
||||
package names for a wide variety of third party projects. This is processed
|
||||
in combination with a project defined list of build pre-requisites to determine
|
||||
the list of native packages to install on each distribution. This can be used
|
||||
to generate dockerfiles, VM package lists and Cirrus CI variables needed to
|
||||
setup build environments across OS distributions with a consistent set of
|
||||
packages present.
|
||||
|
||||
When preparing a patch series that adds a new build pre-requisite to QEMU,
|
||||
updates to various lcitool data files may be required.
|
||||
|
||||
|
||||
Adding new build pre-requisites
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In the simple case where the pre-requisite is already known to ``libvirt-ci``
|
||||
the following steps are needed
|
||||
|
||||
* Edit ``tests/lcitool/projects/qemu.yml`` and add the pre-requisite
|
||||
|
||||
* Run ``make lcitool-refresh`` to re-generate all relevant build environment
|
||||
manifests
|
||||
|
||||
In some cases ``libvirt-ci`` will not know about the build pre-requisite and
|
||||
thus some extra preparation steps will be required first
|
||||
|
||||
* Fork the ``libvirt-ci`` project on gitlab
|
||||
|
||||
* Edit the ``mappings.yml`` change to add an entry for the new build
|
||||
prerequisite, listing its native package name on as many OS distros
|
||||
as practical.
|
||||
|
||||
* Commit the ``mappings.yml`` change and submit a merge request to
|
||||
the ``libvirt-ci`` project, noting in the description that this
|
||||
is a new build pre-requisite desired for use with QEMU
|
||||
|
||||
* CI pipeline will run to validate that the changes to ``mappings.yml``
|
||||
are correct, by attempting to install the newly listed package on
|
||||
all OS distributions supported by ``libvirt-ci``.
|
||||
|
||||
* Once the merge request is accepted, go back to QEMU and update
|
||||
the ``libvirt-ci`` submodule to point to a commit that contains
|
||||
the ``mappings.yml`` update.
|
||||
|
||||
|
||||
Adding new OS distros
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In some cases ``libvirt-ci`` will not know about the OS distro that is
|
||||
desired to be tested. Before adding a new OS distro, discuss the proposed
|
||||
addition:
|
||||
|
||||
* Send a mail to qemu-devel, copying people listed in the
|
||||
MAINTAINERS file for ``Build and test automation``.
|
||||
|
||||
There are limited CI compute resources available to QEMU, so the
|
||||
cost/benefit tradeoff of adding new OS distros needs to be considered.
|
||||
|
||||
* File an issue at https://gitlab.com/libvirt/libvirt-ci/-/issues
|
||||
pointing to the qemu-devel mail thread in the archives.
|
||||
|
||||
This alerts other people who might be interested in the work
|
||||
to avoid duplication, as well as to get feedback from libvirt-ci
|
||||
maintainers on any tips to ease the addition
|
||||
|
||||
Assuming there is agreement to add a new OS distro then
|
||||
|
||||
* Fork the ``libvirt-ci`` project on gitlab
|
||||
|
||||
* Add metadata under ``guests/lcitool/lcitool/ansible/group_vars/``
|
||||
for the new OS distro. There might be code changes required if
|
||||
the OS distro uses a package format not currently known. The
|
||||
``libvirt-ci`` maintainers can advise on this when the issue
|
||||
is file.
|
||||
|
||||
* Edit the ``mappings.yml`` change to update all the existing package
|
||||
entries, providing details of the new OS distro
|
||||
|
||||
* Commit the ``mappings.yml`` change and submit a merge request to
|
||||
the ``libvirt-ci`` project, noting in the description that this
|
||||
is a new build pre-requisite desired for use with QEMU
|
||||
|
||||
* CI pipeline will run to validate that the changes to ``mappings.yml``
|
||||
are correct, by attempting to install the newly listed package on
|
||||
all OS distributions supported by ``libvirt-ci``.
|
||||
|
||||
* Once the merge request is accepted, go back to QEMU and update
|
||||
the ``libvirt-ci`` submodule to point to a commit that contains
|
||||
the ``mappings.yml`` update.
|
||||
|
||||
|
||||
Tests
|
||||
~~~~~
|
||||
|
||||
|
31
docs/interop/dbus-display.rst
Normal file
31
docs/interop/dbus-display.rst
Normal file
@ -0,0 +1,31 @@
|
||||
D-Bus display
|
||||
=============
|
||||
|
||||
QEMU can export the VM display through D-Bus (when started with ``-display
|
||||
dbus``), to allow out-of-process UIs, remote protocol servers or other
|
||||
interactive display usages.
|
||||
|
||||
Various specialized D-Bus interfaces are available on different object paths
|
||||
under ``/org/qemu/Display1/``, depending on the VM configuration.
|
||||
|
||||
QEMU also implements the standard interfaces, such as
|
||||
`org.freedesktop.DBus.Introspectable
|
||||
<https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces>`_.
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
:depth: 1
|
||||
|
||||
.. only:: sphinx4
|
||||
|
||||
.. dbus-doc:: ui/dbus-display1.xml
|
||||
|
||||
.. only:: not sphinx4
|
||||
|
||||
.. warning::
|
||||
Sphinx 4 is required to build D-Bus documentation.
|
||||
|
||||
This is the content of ``ui/dbus-display1.xml``:
|
||||
|
||||
.. literalinclude:: ../../ui/dbus-display1.xml
|
||||
:language: xml
|
@ -2,9 +2,6 @@
|
||||
D-Bus VMState
|
||||
=============
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
The QEMU dbus-vmstate object's aim is to migrate helpers' data running
|
||||
on a QEMU D-Bus bus. (refer to the :doc:`dbus` document for
|
||||
some recommendations on D-Bus usage)
|
||||
@ -26,49 +23,16 @@ dbus-vmstate object can be configured with the expected list of
|
||||
helpers by setting its ``id-list`` property, with a comma-separated
|
||||
``Id`` list.
|
||||
|
||||
Interface
|
||||
=========
|
||||
.. only:: sphinx4
|
||||
|
||||
On object path ``/org/qemu/VMState1``, the following
|
||||
``org.qemu.VMState1`` interface should be implemented:
|
||||
.. dbus-doc:: backends/dbus-vmstate1.xml
|
||||
|
||||
.. code:: xml
|
||||
.. only:: not sphinx4
|
||||
|
||||
<interface name="org.qemu.VMState1">
|
||||
<property name="Id" type="s" access="read"/>
|
||||
<method name="Load">
|
||||
<arg type="ay" name="data" direction="in"/>
|
||||
</method>
|
||||
<method name="Save">
|
||||
<arg type="ay" name="data" direction="out"/>
|
||||
</method>
|
||||
</interface>
|
||||
.. warning::
|
||||
Sphinx 4 is required to build D-Bus documentation.
|
||||
|
||||
"Id" property
|
||||
-------------
|
||||
This is the content of ``backends/dbus-vmstate1.xml``:
|
||||
|
||||
A string that identifies the helper uniquely. (maximum 256 bytes
|
||||
including terminating NUL byte)
|
||||
|
||||
.. note::
|
||||
|
||||
The helper ID namespace is a separate namespace. In particular, it is not
|
||||
related to QEMU "id" used in -object/-device objects.
|
||||
|
||||
Load(in u8[] bytes) method
|
||||
--------------------------
|
||||
|
||||
The method called on destination with the state to restore.
|
||||
|
||||
The helper may be initially started in a waiting state (with
|
||||
an --incoming argument for example), and it may resume on success.
|
||||
|
||||
An error may be returned to the caller.
|
||||
|
||||
Save(out u8[] bytes) method
|
||||
---------------------------
|
||||
|
||||
The method called on the source to get the current state to be
|
||||
migrated. The helper should continue to run normally.
|
||||
|
||||
An error may be returned to the caller.
|
||||
.. literalinclude:: ../../backends/dbus-vmstate1.xml
|
||||
:language: xml
|
||||
|
@ -108,3 +108,5 @@ QEMU Interfaces
|
||||
===============
|
||||
|
||||
:doc:`dbus-vmstate`
|
||||
|
||||
:doc:`dbus-display`
|
||||
|
@ -12,6 +12,7 @@ are useful for making QEMU interoperate with other software.
|
||||
bitmaps
|
||||
dbus
|
||||
dbus-vmstate
|
||||
dbus-display
|
||||
live-block-operations
|
||||
pr-helper
|
||||
qemu-ga
|
||||
@ -21,3 +22,4 @@ are useful for making QEMU interoperate with other software.
|
||||
vhost-user
|
||||
vhost-user-gpu
|
||||
vhost-vdpa
|
||||
virtio-balloon-stats
|
||||
|
@ -1,4 +1,4 @@
|
||||
virtio balloon memory statistics
|
||||
Virtio balloon memory statistics
|
||||
================================
|
||||
|
||||
The virtio balloon driver supports guest memory statistics reporting. These
|
||||
@ -9,10 +9,12 @@ Before querying the available stats, clients first have to enable polling.
|
||||
This is done by writing a time interval value (in seconds) to the
|
||||
guest-stats-polling-interval property. This value can be:
|
||||
|
||||
> 0 enables polling in the specified interval. If polling is already
|
||||
> 0
|
||||
enables polling in the specified interval. If polling is already
|
||||
enabled, the polling time interval is changed to the new value
|
||||
|
||||
0 disables polling. Previous polled statistics are still valid and
|
||||
0
|
||||
disables polling. Previous polled statistics are still valid and
|
||||
can be queried.
|
||||
|
||||
Once polling is enabled, the virtio-balloon device in QEMU will start
|
||||
@ -22,7 +24,7 @@ interval.
|
||||
To retrieve those stats, clients have to query the guest-stats property,
|
||||
which will return a dictionary containing:
|
||||
|
||||
o A key named 'stats', containing all available stats. If the guest
|
||||
* A key named 'stats', containing all available stats. If the guest
|
||||
doesn't support a particular stat, or if it couldn't be retrieved,
|
||||
its value will be -1. Currently, the following stats are supported:
|
||||
|
||||
@ -37,7 +39,7 @@ which will return a dictionary containing:
|
||||
- stat-htlb-pgalloc
|
||||
- stat-htlb-pgfail
|
||||
|
||||
o A key named last-update, which contains the last stats update
|
||||
* A key named last-update, which contains the last stats update
|
||||
timestamp in seconds. Since this timestamp is generated by the host,
|
||||
a buggy guest can't influence its value. The value is 0 if the guest
|
||||
has not updated the stats (yet).
|
||||
@ -61,11 +63,11 @@ It's also important to note the following:
|
||||
respond to the request the timer will never be re-armed, which has
|
||||
the same effect as disabling polling
|
||||
|
||||
Here are a few examples. QEMU is started with '-device virtio-balloon',
|
||||
which generates '/machine/peripheral-anon/device[1]' as the QOM path for
|
||||
Here are a few examples. QEMU is started with ``-device virtio-balloon``,
|
||||
which generates ``/machine/peripheral-anon/device[1]`` as the QOM path for
|
||||
the balloon device.
|
||||
|
||||
Enable polling with 2 seconds interval:
|
||||
Enable polling with 2 seconds interval::
|
||||
|
||||
{ "execute": "qom-set",
|
||||
"arguments": { "path": "/machine/peripheral-anon/device[1]",
|
||||
@ -73,7 +75,7 @@ Enable polling with 2 seconds interval:
|
||||
|
||||
{ "return": {} }
|
||||
|
||||
Change polling to 10 seconds:
|
||||
Change polling to 10 seconds::
|
||||
|
||||
{ "execute": "qom-set",
|
||||
"arguments": { "path": "/machine/peripheral-anon/device[1]",
|
||||
@ -81,7 +83,7 @@ Change polling to 10 seconds:
|
||||
|
||||
{ "return": {} }
|
||||
|
||||
Get stats:
|
||||
Get stats::
|
||||
|
||||
{ "execute": "qom-get",
|
||||
"arguments": { "path": "/machine/peripheral-anon/device[1]",
|
||||
@ -100,7 +102,7 @@ Get stats:
|
||||
}
|
||||
}
|
||||
|
||||
Disable polling:
|
||||
Disable polling::
|
||||
|
||||
{ "execute": "qom-set",
|
||||
"arguments": { "path": "/machine/peripheral-anon/device[1]",
|
@ -1,30 +0,0 @@
|
||||
POWER (PAPR) Protected Execution Facility (PEF)
|
||||
===============================================
|
||||
|
||||
Protected Execution Facility (PEF), also known as Secure Guest support
|
||||
is a feature found on IBM POWER9 and POWER10 processors.
|
||||
|
||||
If a suitable firmware including an Ultravisor is installed, it adds
|
||||
an extra memory protection mode to the CPU. The ultravisor manages a
|
||||
pool of secure memory which cannot be accessed by the hypervisor.
|
||||
|
||||
When this feature is enabled in QEMU, a guest can use ultracalls to
|
||||
enter "secure mode". This transfers most of its memory to secure
|
||||
memory, where it cannot be eavesdropped by a compromised hypervisor.
|
||||
|
||||
Launching
|
||||
---------
|
||||
|
||||
To launch a guest which will be permitted to enter PEF secure mode:
|
||||
|
||||
# ${QEMU} \
|
||||
-object pef-guest,id=pef0 \
|
||||
-machine confidential-guest-support=pef0 \
|
||||
...
|
||||
|
||||
Live Migration
|
||||
----------------
|
||||
|
||||
Live migration is not yet implemented for PEF guests. For
|
||||
consistency, we currently prevent migration if the PEF feature is
|
||||
enabled, whether or not the guest has actually entered secure mode.
|
@ -1,13 +1,12 @@
|
||||
======================
|
||||
sPAPR hypervisor calls
|
||||
----------------------
|
||||
======================
|
||||
|
||||
When used with the ``pseries`` machine type, ``qemu-system-ppc64`` implements
|
||||
a set of hypervisor calls (a.k.a. hcalls) defined in the `Linux on Power
|
||||
Architecture Reference document (LoPAR)
|
||||
<https://cdn.openpowerfoundation.org/wp-content/uploads/2020/07/LoPAR-20200812.pdf>`_.
|
||||
This document is a subset of the Power Architecture Platform Reference (PAPR+)
|
||||
specification (IBM internal only), which is what PowerVM, the IBM proprietary
|
||||
hypervisor, adheres to.
|
||||
a set of hypervisor calls (a.k.a. hcalls) defined in the Linux on Power
|
||||
Architecture Reference ([LoPAR]_) document. This document is a subset of the
|
||||
Power Architecture Platform Reference (PAPR+) specification (IBM internal only),
|
||||
which is what PowerVM, the IBM proprietary hypervisor, adheres to.
|
||||
|
||||
The subset in LoPAR is selected based on the requirements of Linux as a guest.
|
||||
|
||||
@ -18,8 +17,8 @@ running in the guest and QEMU.
|
||||
All those hypercalls start at hcall number 0xf000 which correspond
|
||||
to an implementation specific range in PAPR.
|
||||
|
||||
H_RTAS (0xf000)
|
||||
^^^^^^^^^^^^^^^
|
||||
``H_RTAS (0xf000)``
|
||||
===================
|
||||
|
||||
RTAS stands for Run-Time Abstraction Sercies and is a set of runtime services
|
||||
generally provided by the firmware inside the guest to the operating system. It
|
||||
@ -44,8 +43,8 @@ Returns:
|
||||
|
||||
``H_PARAMETER``: Unknown token.
|
||||
|
||||
H_LOGICAL_MEMOP (0xf001)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
``H_LOGICAL_MEMOP (0xf001)``
|
||||
============================
|
||||
|
||||
When the guest runs in "real mode" (in powerpc terminology this means with MMU
|
||||
disabled, i.e. guest effective address equals to guest physical address), it
|
||||
|
510
docs/specs/ppc-spapr-hotplug.rst
Normal file
510
docs/specs/ppc-spapr-hotplug.rst
Normal file
@ -0,0 +1,510 @@
|
||||
=============================
|
||||
sPAPR Dynamic Reconfiguration
|
||||
=============================
|
||||
|
||||
sPAPR or pSeries guests make use of a facility called dynamic reconfiguration
|
||||
to handle hot plugging of dynamic "physical" resources like PCI cards, or
|
||||
"logical"/para-virtual resources like memory, CPUs, and "physical"
|
||||
host-bridges, which are generally managed by the host/hypervisor and provided
|
||||
to guests as virtualized resources. The specifics of dynamic reconfiguration
|
||||
are documented extensively in section 13 of the Linux on Power Architecture
|
||||
Reference document ([LoPAR]_). This document provides a summary of that
|
||||
information as it applies to the implementation within QEMU.
|
||||
|
||||
Dynamic-reconfiguration Connectors
|
||||
==================================
|
||||
|
||||
To manage hot plug/unplug of these resources, a firmware abstraction known as
|
||||
a Dynamic Resource Connector (DRC) is used to assign a particular dynamic
|
||||
resource to the guest, and provide an interface for the guest to manage
|
||||
configuration/removal of the resource associated with it.
|
||||
|
||||
Device tree description of DRCs
|
||||
===============================
|
||||
|
||||
A set of four Open Firmware device tree array properties are used to describe
|
||||
the name/index/power-domain/type of each DRC allocated to a guest at
|
||||
boot time. There may be multiple sets of these arrays, rooted at different
|
||||
paths in the device tree depending on the type of resource the DRCs manage.
|
||||
|
||||
In some cases, the DRCs themselves may be provided by a dynamic resource,
|
||||
such as the DRCs managing PCI slots on a hot plugged PHB. In this case the
|
||||
arrays would be fetched as part of the device tree retrieval interfaces
|
||||
for hot plugged resources described under :ref:`guest-host-interface`.
|
||||
|
||||
The array properties are described below. Each entry/element in an array
|
||||
describes the DRC identified by the element in the corresponding position
|
||||
of ``ibm,drc-indexes``:
|
||||
|
||||
``ibm,drc-names``
|
||||
-----------------
|
||||
|
||||
First 4-bytes: big-endian (BE) encoded integer denoting the number of entries.
|
||||
|
||||
Each entry: a NULL-terminated ``<name>`` string encoded as a byte array.
|
||||
|
||||
``<name>`` values for logical/virtual resources are defined in the Linux on
|
||||
Power Architecture Reference ([LoPAR]_) section 13.5.2.4, and basically
|
||||
consist of the type of the resource followed by a space and a numerical
|
||||
value that's unique across resources of that type.
|
||||
|
||||
``<name>`` values for "physical" resources such as PCI or VIO devices are
|
||||
defined as being "location codes", which are the "location labels" of each
|
||||
encapsulating device, starting from the chassis down to the individual slot
|
||||
for the device, concatenated by a hyphen. This provides a mapping of
|
||||
resources to a physical location in a chassis for debugging purposes. For
|
||||
QEMU, this mapping is less important, so we assign a location code that
|
||||
conforms to naming specifications, but is simply a location label for the
|
||||
slot by itself to simplify the implementation. The naming convention for
|
||||
location labels is documented in detail in the [LoPAR]_ section 12.3.1.5,
|
||||
and in our case amounts to using ``C<n>`` for PCI/VIO device slots, where
|
||||
``<n>`` is unique across all PCI/VIO device slots.
|
||||
|
||||
``ibm,drc-indexes``
|
||||
-------------------
|
||||
|
||||
First 4-bytes: BE-encoded integer denoting the number of entries.
|
||||
|
||||
Each 4-byte entry: BE-encoded ``<index>`` integer that is unique across all
|
||||
DRCs in the machine.
|
||||
|
||||
``<index>`` is arbitrary, but in the case of QEMU we try to maintain the
|
||||
convention used to assign them to pSeries guests on pHyp (the hypervisor
|
||||
portion of PowerVM):
|
||||
|
||||
``bit[31:28]``: integer encoding of ``<type>``, where ``<type>`` is:
|
||||
|
||||
``1`` for CPU resource.
|
||||
|
||||
``2`` for PHB resource.
|
||||
|
||||
``3`` for VIO resource.
|
||||
|
||||
``4`` for PCI resource.
|
||||
|
||||
``8`` for memory resource.
|
||||
|
||||
``bit[27:0]``: integer encoding of ``<id>``, where ``<id>`` is unique
|
||||
across all resources of specified type.
|
||||
|
||||
``ibm,drc-power-domains``
|
||||
-------------------------
|
||||
|
||||
First 4-bytes: BE-encoded integer denoting the number of entries.
|
||||
|
||||
Each 4-byte entry: 32-bit, BE-encoded ``<index>`` integer that specifies the
|
||||
power domain the resource will be assigned to. In the case of QEMU we
|
||||
associated all resources with a "live insertion" domain, where the power is
|
||||
assumed to be managed automatically. The integer value for this domain is a
|
||||
special value of ``-1``.
|
||||
|
||||
|
||||
``ibm,drc-types``
|
||||
-----------------
|
||||
|
||||
First 4-bytes: BE-encoded integer denoting the number of entries.
|
||||
|
||||
Each entry: a NULL-terminated ``<type>`` string encoded as a byte array.
|
||||
``<type>`` is assigned as follows:
|
||||
|
||||
"CPU" for a CPU.
|
||||
|
||||
"PHB" for a physical host-bridge.
|
||||
|
||||
"SLOT" for a VIO slot.
|
||||
|
||||
"28" for a PCI slot.
|
||||
|
||||
"MEM" for memory resource.
|
||||
|
||||
.. _guest-host-interface:
|
||||
|
||||
Guest->Host interface to manage dynamic resources
|
||||
=================================================
|
||||
|
||||
Each DRC is given a globally unique DRC index, and resources associated with a
|
||||
particular DRC are configured/managed by the guest via a number of RTAS calls
|
||||
which reference individual DRCs based on the DRC index. This can be considered
|
||||
the guest->host interface.
|
||||
|
||||
``rtas-set-power-level``
|
||||
------------------------
|
||||
|
||||
Set the power level for a specified power domain.
|
||||
|
||||
``arg[0]``: integer identifying power domain.
|
||||
|
||||
``arg[1]``: new power level for the domain, ``0-100``.
|
||||
|
||||
``output[0]``: status, ``0`` on success.
|
||||
|
||||
``output[1]``: power level after command.
|
||||
|
||||
``rtas-get-power-level``
|
||||
------------------------
|
||||
|
||||
Get the power level for a specified power domain.
|
||||
|
||||
``arg[0]``: integer identifying power domain.
|
||||
|
||||
``output[0]``: status, ``0`` on success.
|
||||
|
||||
``output[1]``: current power level.
|
||||
|
||||
``rtas-set-indicator``
|
||||
----------------------
|
||||
|
||||
Set the state of an indicator or sensor.
|
||||
|
||||
``arg[0]``: integer identifying sensor/indicator type.
|
||||
|
||||
``arg[1]``: index of sensor, for DR-related sensors this is generally the DRC
|
||||
index.
|
||||
|
||||
``arg[2]``: desired sensor value.
|
||||
|
||||
``output[0]``: status, ``0`` on success.
|
||||
|
||||
For the purpose of this document we focus on the indicator/sensor types
|
||||
associated with a DRC. The types are:
|
||||
|
||||
* ``9001``: ``isolation-state``, controls/indicates whether a device has been
|
||||
made accessible to a guest. Supported sensor values:
|
||||
|
||||
``0``: ``isolate``, device is made inaccessible by guest OS.
|
||||
|
||||
``1``: ``unisolate``, device is made available to guest OS.
|
||||
|
||||
* ``9002``: ``dr-indicator``, controls "visual" indicator associated with
|
||||
device. Supported sensor values:
|
||||
|
||||
``0``: ``inactive``, resource may be safely removed.
|
||||
|
||||
``1``: ``active``, resource is in use and cannot be safely removed.
|
||||
|
||||
``2``: ``identify``, used to visually identify slot for interactive hot plug.
|
||||
|
||||
``3``: ``action``, in most cases, used in the same manner as identify.
|
||||
|
||||
* ``9003``: ``allocation-state``, generally only used for "logical" DR resources
|
||||
to request the allocation/deallocation of a resource prior to acquiring it via
|
||||
``isolation-state->unisolate``, or after releasing it via
|
||||
``isolation-state->isolate``, respectively. For "physical" DR (like PCI
|
||||
hot plug/unplug) the pre-allocation of the resource is implied and this sensor
|
||||
is unused. Supported sensor values:
|
||||
|
||||
``0``: ``unusable``, tell firmware/system the resource can be
|
||||
unallocated/reclaimed and added back to the system resource pool.
|
||||
|
||||
``1``: ``usable``, request the resource be allocated/reserved for use by
|
||||
guest OS.
|
||||
|
||||
``2``: ``exchange``, used to allocate a spare resource to use for fail-over
|
||||
in certain situations. Unused in QEMU.
|
||||
|
||||
``3``: ``recover``, used to reclaim a previously allocated resource that's
|
||||
not currently allocated to the guest OS. Unused in QEMU.
|
||||
|
||||
``rtas-get-sensor-state:``
|
||||
--------------------------
|
||||
|
||||
Used to read an indicator or sensor value.
|
||||
|
||||
``arg[0]``: integer identifying sensor/indicator type.
|
||||
|
||||
``arg[1]``: index of sensor, for DR-related sensors this is generally the DRC
|
||||
index
|
||||
|
||||
``output[0]``: status, 0 on success
|
||||
|
||||
For DR-related operations, the only noteworthy sensor is ``dr-entity-sense``,
|
||||
which has a type value of ``9003``, as ``allocation-state`` does in the case of
|
||||
``rtas-set-indicator``. The semantics/encodings of the sensor values are
|
||||
distinct however.
|
||||
|
||||
Supported sensor values for ``dr-entity-sense`` (``9003``) sensor:
|
||||
|
||||
``0``: empty.
|
||||
|
||||
For physical resources: DRC/slot is empty.
|
||||
|
||||
For logical resources: unused.
|
||||
|
||||
``1``: present.
|
||||
|
||||
For physical resources: DRC/slot is populated with a device/resource.
|
||||
|
||||
For logical resources: resource has been allocated to the DRC.
|
||||
|
||||
``2``: unusable.
|
||||
|
||||
For physical resources: unused.
|
||||
|
||||
For logical resources: DRC has no resource allocated to it.
|
||||
|
||||
``3``: exchange.
|
||||
|
||||
For physical resources: unused.
|
||||
|
||||
For logical resources: resource available for exchange (see
|
||||
``allocation-state`` sensor semantics above).
|
||||
|
||||
``4``: recovery.
|
||||
|
||||
For physical resources: unused.
|
||||
|
||||
For logical resources: resource available for recovery (see
|
||||
``allocation-state`` sensor semantics above).
|
||||
|
||||
``rtas-ibm-configure-connector``
|
||||
--------------------------------
|
||||
|
||||
Used to fetch an OpenFirmware device tree description of the resource associated
|
||||
with a particular DRC.
|
||||
|
||||
``arg[0]``: guest physical address of 4096-byte work area buffer.
|
||||
|
||||
``arg[1]``: 0, or address of additional 4096-byte work area buffer; only
|
||||
non-zero if a prior RTAS response indicated a need for additional memory.
|
||||
|
||||
``output[0]``: status:
|
||||
|
||||
``0``: completed transmittal of device tree node.
|
||||
|
||||
``1``: instruct guest to prepare for next device tree sibling node.
|
||||
|
||||
``2``: instruct guest to prepare for next device tree child node.
|
||||
|
||||
``3``: instruct guest to prepare for next device tree property.
|
||||
|
||||
``4``: instruct guest to ascend to parent device tree node.
|
||||
|
||||
``5``: instruct guest to provide additional work-area buffer via ``arg[1]``.
|
||||
|
||||
``990x``: instruct guest that operation took too long and to try again
|
||||
later.
|
||||
|
||||
The DRC index is encoded in the first 4-bytes of the first work area buffer.
|
||||
Work area (``wa``) layout, using 4-byte offsets:
|
||||
|
||||
``wa[0]``: DRC index of the DRC to fetch device tree nodes from.
|
||||
|
||||
``wa[1]``: ``0`` (hard-coded).
|
||||
|
||||
``wa[2]``:
|
||||
|
||||
For next-sibling/next-child response:
|
||||
|
||||
``wa`` offset of null-terminated string denoting the new node's name.
|
||||
|
||||
For next-property response:
|
||||
|
||||
``wa`` offset of null-terminated string denoting new property's name.
|
||||
|
||||
``wa[3]``: for next-property response (unused otherwise):
|
||||
|
||||
Byte-length of new property's value.
|
||||
|
||||
``wa[4]``: for next-property response (unused otherwise):
|
||||
|
||||
New property's value, encoded as an OFDT-compatible byte array.
|
||||
|
||||
Hot plug/unplug events
|
||||
======================
|
||||
|
||||
For most DR operations, the hypervisor will issue host->guest add/remove events
|
||||
using the EPOW/check-exception notification framework, where the host issues a
|
||||
check-exception interrupt, then provides an RTAS event log via an
|
||||
rtas-check-exception call issued by the guest in response. This framework is
|
||||
documented by PAPR+ v2.7, and already use in by QEMU for generating powerdown
|
||||
requests via EPOW events.
|
||||
|
||||
For DR, this framework has been extended to include hotplug events, which were
|
||||
previously unneeded due to direct manipulation of DR-related guest userspace
|
||||
tools by host-level management such as an HMC. This level of management is not
|
||||
applicable to KVM on Power, hence the reason for extending the notification
|
||||
framework to support hotplug events.
|
||||
|
||||
The format for these EPOW-signalled events is described below under
|
||||
:ref:`hot-plug-unplug-event-structure`. Note that these events are not formally
|
||||
part of the PAPR+ specification, and have been superseded by a newer format,
|
||||
also described below under :ref:`hot-plug-unplug-event-structure`, and so are
|
||||
now deemed a "legacy" format. The formats are similar, but the "modern" format
|
||||
contains additional fields/flags, which are denoted for the purposes of this
|
||||
documentation with ``#ifdef GUEST_SUPPORTS_MODERN`` guards.
|
||||
|
||||
QEMU should assume support only for "legacy" fields/flags unless the guest
|
||||
advertises support for the "modern" format via
|
||||
``ibm,client-architecture-support`` hcall by setting byte 5, bit 6 of it's
|
||||
``ibm,architecture-vec-5`` option vector structure (as described by [LoPAR]_,
|
||||
section B.5.2.3). As with "legacy" format events, "modern" format events are
|
||||
surfaced to the guest via check-exception RTAS calls, but use a dedicated event
|
||||
source to signal the guest. This event source is advertised to the guest by the
|
||||
addition of a ``hot-plug-events`` node under ``/event-sources`` node of the
|
||||
guest's device tree using the standard format described in [LoPAR]_,
|
||||
section B.5.12.2.
|
||||
|
||||
.. _hot-plug-unplug-event-structure:
|
||||
|
||||
Hot plug/unplug event structure
|
||||
===============================
|
||||
|
||||
The hot plug specific payload in QEMU is implemented as follows (with all values
|
||||
encoded in big-endian format):
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct rtas_event_log_v6_hp {
|
||||
#define SECTION_ID_HOTPLUG 0x4850 /* HP */
|
||||
struct section_header {
|
||||
uint16_t section_id; /* set to SECTION_ID_HOTPLUG */
|
||||
uint16_t section_length; /* sizeof(rtas_event_log_v6_hp),
|
||||
* plus the length of the DRC name
|
||||
* if a DRC name identifier is
|
||||
* specified for hotplug_identifier
|
||||
*/
|
||||
uint8_t section_version; /* version 1 */
|
||||
uint8_t section_subtype; /* unused */
|
||||
uint16_t creator_component_id; /* unused */
|
||||
} hdr;
|
||||
#define RTAS_LOG_V6_HP_TYPE_CPU 1
|
||||
#define RTAS_LOG_V6_HP_TYPE_MEMORY 2
|
||||
#define RTAS_LOG_V6_HP_TYPE_SLOT 3
|
||||
#define RTAS_LOG_V6_HP_TYPE_PHB 4
|
||||
#define RTAS_LOG_V6_HP_TYPE_PCI 5
|
||||
uint8_t hotplug_type; /* type of resource/device */
|
||||
#define RTAS_LOG_V6_HP_ACTION_ADD 1
|
||||
#define RTAS_LOG_V6_HP_ACTION_REMOVE 2
|
||||
uint8_t hotplug_action; /* action (add/remove) */
|
||||
#define RTAS_LOG_V6_HP_ID_DRC_NAME 1
|
||||
#define RTAS_LOG_V6_HP_ID_DRC_INDEX 2
|
||||
#define RTAS_LOG_V6_HP_ID_DRC_COUNT 3
|
||||
#ifdef GUEST_SUPPORTS_MODERN
|
||||
#define RTAS_LOG_V6_HP_ID_DRC_COUNT_INDEXED 4
|
||||
#endif
|
||||
uint8_t hotplug_identifier; /* type of the resource identifier,
|
||||
* which serves as the discriminator
|
||||
* for the 'drc' union field below
|
||||
*/
|
||||
#ifdef GUEST_SUPPORTS_MODERN
|
||||
uint8_t capabilities; /* capability flags, currently unused
|
||||
* by QEMU
|
||||
*/
|
||||
#else
|
||||
uint8_t reserved;
|
||||
#endif
|
||||
union {
|
||||
uint32_t index; /* DRC index of resource to take action
|
||||
* on
|
||||
*/
|
||||
uint32_t count; /* number of DR resources to take
|
||||
* action on (guest chooses which)
|
||||
*/
|
||||
#ifdef GUEST_SUPPORTS_MODERN
|
||||
struct {
|
||||
uint32_t count; /* number of DR resources to take
|
||||
* action on
|
||||
*/
|
||||
uint32_t index; /* DRC index of first resource to take
|
||||
* action on. guest will take action
|
||||
* on DRC index <index> through
|
||||
* DRC index <index + count - 1> in
|
||||
* sequential order
|
||||
*/
|
||||
} count_indexed;
|
||||
#endif
|
||||
char name[1]; /* string representing the name of the
|
||||
* DRC to take action on
|
||||
*/
|
||||
} drc;
|
||||
} QEMU_PACKED;
|
||||
|
||||
``ibm,lrdr-capacity``
|
||||
=====================
|
||||
|
||||
``ibm,lrdr-capacity`` is a property in the /rtas device tree node that
|
||||
identifies the dynamic reconfiguration capabilities of the guest. It consists
|
||||
of a triple consisting of ``<phys>``, ``<size>`` and ``<maxcpus>``.
|
||||
|
||||
``<phys>``, encoded in BE format represents the maximum address in bytes and
|
||||
hence the maximum memory that can be allocated to the guest.
|
||||
|
||||
``<size>``, encoded in BE format represents the size increments in which
|
||||
memory can be hot-plugged to the guest.
|
||||
|
||||
``<maxcpus>``, a BE-encoded integer, represents the maximum number of
|
||||
processors that the guest can have.
|
||||
|
||||
``pseries`` guests use this property to note the maximum allowed CPUs for the
|
||||
guest.
|
||||
|
||||
``ibm,dynamic-reconfiguration-memory``
|
||||
======================================
|
||||
|
||||
``ibm,dynamic-reconfiguration-memory`` is a device tree node that represents
|
||||
dynamically reconfigurable logical memory blocks (LMB). This node is generated
|
||||
only when the guest advertises the support for it via
|
||||
``ibm,client-architecture-support`` call. Memory that is not dynamically
|
||||
reconfigurable is represented by ``/memory`` nodes. The properties of this node
|
||||
that are of interest to the sPAPR memory hotplug implementation in QEMU are
|
||||
described here.
|
||||
|
||||
``ibm,lmb-size``
|
||||
----------------
|
||||
|
||||
This 64-bit integer defines the size of each dynamically reconfigurable LMB.
|
||||
|
||||
``ibm,associativity-lookup-arrays``
|
||||
-----------------------------------
|
||||
|
||||
This property defines a lookup array in which the NUMA associativity
|
||||
information for each LMB can be found. It is a property encoded array
|
||||
that begins with an integer M, the number of associativity lists followed
|
||||
by an integer N, the number of entries per associativity list and terminated
|
||||
by M associativity lists each of length N integers.
|
||||
|
||||
This property provides the same information as given by ``ibm,associativity``
|
||||
property in a ``/memory`` node. Each assigned LMB has an index value between
|
||||
0 and M-1 which is used as an index into this table to select which
|
||||
associativity list to use for the LMB. This index value for each LMB is defined
|
||||
in ``ibm,dynamic-memory`` property.
|
||||
|
||||
``ibm,dynamic-memory``
|
||||
----------------------
|
||||
|
||||
This property describes the dynamically reconfigurable memory. It is a
|
||||
property encoded array that has an integer N, the number of LMBs followed
|
||||
by N LMB list entries.
|
||||
|
||||
Each LMB list entry consists of the following elements:
|
||||
|
||||
- Logical address of the start of the LMB encoded as a 64-bit integer. This
|
||||
corresponds to ``reg`` property in ``/memory`` node.
|
||||
- DRC index of the LMB that corresponds to ``ibm,my-drc-index`` property
|
||||
in a ``/memory`` node.
|
||||
- Four bytes reserved for expansion.
|
||||
- Associativity list index for the LMB that is used as an index into
|
||||
``ibm,associativity-lookup-arrays`` property described earlier. This is used
|
||||
to retrieve the right associativity list to be used for this LMB.
|
||||
- A 32-bit flags word. The bit at bit position ``0x00000008`` defines whether
|
||||
the LMB is assigned to the partition as of boot time.
|
||||
|
||||
``ibm,dynamic-memory-v2``
|
||||
-------------------------
|
||||
|
||||
This property describes the dynamically reconfigurable memory. This is
|
||||
an alternate and newer way to describe dynamically reconfigurable memory.
|
||||
It is a property encoded array that has an integer N (the number of
|
||||
LMB set entries) followed by N LMB set entries. There is an LMB set entry
|
||||
for each sequential group of LMBs that share common attributes.
|
||||
|
||||
Each LMB set entry consists of the following elements:
|
||||
|
||||
- Number of sequential LMBs in the entry represented by a 32-bit integer.
|
||||
- Logical address of the first LMB in the set encoded as a 64-bit integer.
|
||||
- DRC index of the first LMB in the set.
|
||||
- Associativity list index that is used as an index into
|
||||
``ibm,associativity-lookup-arrays`` property described earlier. This
|
||||
is used to retrieve the right associativity list to be used for all
|
||||
the LMBs in this set.
|
||||
- A 32-bit flags word that applies to all the LMBs in the set.
|
@ -1,409 +0,0 @@
|
||||
= sPAPR Dynamic Reconfiguration =
|
||||
|
||||
sPAPR/"pseries" guests make use of a facility called dynamic-reconfiguration
|
||||
to handle hotplugging of dynamic "physical" resources like PCI cards, or
|
||||
"logical"/paravirtual resources like memory, CPUs, and "physical"
|
||||
host-bridges, which are generally managed by the host/hypervisor and provided
|
||||
to guests as virtualized resources. The specifics of dynamic-reconfiguration
|
||||
are documented extensively in PAPR+ v2.7, Section 13.1. This document
|
||||
provides a summary of that information as it applies to the implementation
|
||||
within QEMU.
|
||||
|
||||
== Dynamic-reconfiguration Connectors ==
|
||||
|
||||
To manage hotplug/unplug of these resources, a firmware abstraction known as
|
||||
a Dynamic Resource Connector (DRC) is used to assign a particular dynamic
|
||||
resource to the guest, and provide an interface for the guest to manage
|
||||
configuration/removal of the resource associated with it.
|
||||
|
||||
== Device-tree description of DRCs ==
|
||||
|
||||
A set of 4 Open Firmware device tree array properties are used to describe
|
||||
the name/index/power-domain/type of each DRC allocated to a guest at
|
||||
boot-time. There may be multiple sets of these arrays, rooted at different
|
||||
paths in the device tree depending on the type of resource the DRCs manage.
|
||||
|
||||
In some cases, the DRCs themselves may be provided by a dynamic resource,
|
||||
such as the DRCs managing PCI slots on a hotplugged PHB. In this case the
|
||||
arrays would be fetched as part of the device tree retrieval interfaces
|
||||
for hotplugged resources described under "Guest->Host interface".
|
||||
|
||||
The array properties are described below. Each entry/element in an array
|
||||
describes the DRC identified by the element in the corresponding position
|
||||
of ibm,drc-indexes:
|
||||
|
||||
ibm,drc-names:
|
||||
first 4-bytes: BE-encoded integer denoting the number of entries
|
||||
each entry: a NULL-terminated <name> string encoded as a byte array
|
||||
|
||||
<name> values for logical/virtual resources are defined in PAPR+ v2.7,
|
||||
Section 13.5.2.4, and basically consist of the type of the resource
|
||||
followed by a space and a numerical value that's unique across resources
|
||||
of that type.
|
||||
|
||||
<name> values for "physical" resources such as PCI or VIO devices are
|
||||
defined as being "location codes", which are the "location labels" of
|
||||
each encapsulating device, starting from the chassis down to the
|
||||
individual slot for the device, concatenated by a hyphen. This provides
|
||||
a mapping of resources to a physical location in a chassis for debugging
|
||||
purposes. For QEMU, this mapping is less important, so we assign a
|
||||
location code that conforms to naming specifications, but is simply a
|
||||
location label for the slot by itself to simplify the implementation.
|
||||
The naming convention for location labels is documented in detail in
|
||||
PAPR+ v2.7, Section 12.3.1.5, and in our case amounts to using "C<n>"
|
||||
for PCI/VIO device slots, where <n> is unique across all PCI/VIO
|
||||
device slots.
|
||||
|
||||
ibm,drc-indexes:
|
||||
first 4-bytes: BE-encoded integer denoting the number of entries
|
||||
each 4-byte entry: BE-encoded <index> integer that is unique across all DRCs
|
||||
in the machine
|
||||
|
||||
<index> is arbitrary, but in the case of QEMU we try to maintain the
|
||||
convention used to assign them to pSeries guests on pHyp:
|
||||
|
||||
bit[31:28]: integer encoding of <type>, where <type> is:
|
||||
1 for CPU resource
|
||||
2 for PHB resource
|
||||
3 for VIO resource
|
||||
4 for PCI resource
|
||||
8 for Memory resource
|
||||
bit[27:0]: integer encoding of <id>, where <id> is unique across
|
||||
all resources of specified type
|
||||
|
||||
ibm,drc-power-domains:
|
||||
first 4-bytes: BE-encoded integer denoting the number of entries
|
||||
each 4-byte entry: 32-bit, BE-encoded <index> integer that specifies the
|
||||
power domain the resource will be assigned to. In the case of QEMU
|
||||
we associated all resources with a "live insertion" domain, where the
|
||||
power is assumed to be managed automatically. The integer value for
|
||||
this domain is a special value of -1.
|
||||
|
||||
|
||||
ibm,drc-types:
|
||||
first 4-bytes: BE-encoded integer denoting the number of entries
|
||||
each entry: a NULL-terminated <type> string encoded as a byte array
|
||||
|
||||
<type> is assigned as follows:
|
||||
"CPU" for a CPU
|
||||
"PHB" for a physical host-bridge
|
||||
"SLOT" for a VIO slot
|
||||
"28" for a PCI slot
|
||||
"MEM" for memory resource
|
||||
|
||||
== Guest->Host interface to manage dynamic resources ==
|
||||
|
||||
Each DRC is given a globally unique DRC Index, and resources associated with
|
||||
a particular DRC are configured/managed by the guest via a number of RTAS
|
||||
calls which reference individual DRCs based on the DRC index. This can be
|
||||
considered the guest->host interface.
|
||||
|
||||
rtas-set-power-level:
|
||||
arg[0]: integer identifying power domain
|
||||
arg[1]: new power level for the domain, 0-100
|
||||
output[0]: status, 0 on success
|
||||
output[1]: power level after command
|
||||
|
||||
Set the power level for a specified power domain
|
||||
|
||||
rtas-get-power-level:
|
||||
arg[0]: integer identifying power domain
|
||||
output[0]: status, 0 on success
|
||||
output[1]: current power level
|
||||
|
||||
Get the power level for a specified power domain
|
||||
|
||||
rtas-set-indicator:
|
||||
arg[0]: integer identifying sensor/indicator type
|
||||
arg[1]: index of sensor, for DR-related sensors this is generally the
|
||||
DRC index
|
||||
arg[2]: desired sensor value
|
||||
output[0]: status, 0 on success
|
||||
|
||||
Set the state of an indicator or sensor. For the purpose of this document we
|
||||
focus on the indicator/sensor types associated with a DRC. The types are:
|
||||
|
||||
9001: isolation-state, controls/indicates whether a device has been made
|
||||
accessible to a guest
|
||||
|
||||
supported sensor values:
|
||||
0: isolate, device is made unaccessible by guest OS
|
||||
1: unisolate, device is made available to guest OS
|
||||
|
||||
9002: dr-indicator, controls "visual" indicator associated with device
|
||||
|
||||
supported sensor values:
|
||||
0: inactive, resource may be safely removed
|
||||
1: active, resource is in use and cannot be safely removed
|
||||
2: identify, used to visually identify slot for interactive hotplug
|
||||
3: action, in most cases, used in the same manner as identify
|
||||
|
||||
9003: allocation-state, generally only used for "logical" DR resources to
|
||||
request the allocation/deallocation of a resource prior to acquiring
|
||||
it via isolation-state->unisolate, or after releasing it via
|
||||
isolation-state->isolate, respectively. for "physical" DR (like PCI
|
||||
hotplug/unplug) the pre-allocation of the resource is implied and
|
||||
this sensor is unused.
|
||||
|
||||
supported sensor values:
|
||||
0: unusable, tell firmware/system the resource can be
|
||||
unallocated/reclaimed and added back to the system resource pool
|
||||
1: usable, request the resource be allocated/reserved for use by
|
||||
guest OS
|
||||
2: exchange, used to allocate a spare resource to use for fail-over
|
||||
in certain situations. unused in QEMU
|
||||
3: recover, used to reclaim a previously allocated resource that's
|
||||
not currently allocated to the guest OS. unused in QEMU
|
||||
|
||||
rtas-get-sensor-state:
|
||||
arg[0]: integer identifying sensor/indicator type
|
||||
arg[1]: index of sensor, for DR-related sensors this is generally the
|
||||
DRC index
|
||||
output[0]: status, 0 on success
|
||||
|
||||
Used to read an indicator or sensor value.
|
||||
|
||||
For DR-related operations, the only noteworthy sensor is dr-entity-sense,
|
||||
which has a type value of 9003, as allocation-state does in the case of
|
||||
rtas-set-indicator. The semantics/encodings of the sensor values are distinct
|
||||
however:
|
||||
|
||||
supported sensor values for dr-entity-sense (9003) sensor:
|
||||
0: empty,
|
||||
for physical resources: DRC/slot is empty
|
||||
for logical resources: unused
|
||||
1: present,
|
||||
for physical resources: DRC/slot is populated with a device/resource
|
||||
for logical resources: resource has been allocated to the DRC
|
||||
2: unusable,
|
||||
for physical resources: unused
|
||||
for logical resources: DRC has no resource allocated to it
|
||||
3: exchange,
|
||||
for physical resources: unused
|
||||
for logical resources: resource available for exchange (see
|
||||
allocation-state sensor semantics above)
|
||||
4: recovery,
|
||||
for physical resources: unused
|
||||
for logical resources: resource available for recovery (see
|
||||
allocation-state sensor semantics above)
|
||||
|
||||
rtas-ibm-configure-connector:
|
||||
arg[0]: guest physical address of 4096-byte work area buffer
|
||||
arg[1]: 0, or address of additional 4096-byte work area buffer. only non-zero
|
||||
if a prior RTAS response indicated a need for additional memory
|
||||
output[0]: status:
|
||||
0: completed transmittal of device-tree node
|
||||
1: instruct guest to prepare for next DT sibling node
|
||||
2: instruct guest to prepare for next DT child node
|
||||
3: instruct guest to prepare for next DT property
|
||||
4: instruct guest to ascend to parent DT node
|
||||
5: instruct guest to provide additional work-area buffer
|
||||
via arg[1]
|
||||
990x: instruct guest that operation took too long and to try
|
||||
again later
|
||||
|
||||
Used to fetch an OF device-tree description of the resource associated with
|
||||
a particular DRC. The DRC index is encoded in the first 4-bytes of the first
|
||||
work area buffer.
|
||||
|
||||
Work area layout, using 4-byte offsets:
|
||||
wa[0]: DRC index of the DRC to fetch device-tree nodes from
|
||||
wa[1]: 0 (hard-coded)
|
||||
wa[2]: for next-sibling/next-child response:
|
||||
wa offset of null-terminated string denoting the new node's name
|
||||
for next-property response:
|
||||
wa offset of null-terminated string denoting new property's name
|
||||
wa[3]: for next-property response (unused otherwise):
|
||||
byte-length of new property's value
|
||||
wa[4]: for next-property response (unused otherwise):
|
||||
new property's value, encoded as an OFDT-compatible byte array
|
||||
|
||||
== hotplug/unplug events ==
|
||||
|
||||
For most DR operations, the hypervisor will issue host->guest add/remove events
|
||||
using the EPOW/check-exception notification framework, where the host issues a
|
||||
check-exception interrupt, then provides an RTAS event log via an
|
||||
rtas-check-exception call issued by the guest in response. This framework is
|
||||
documented by PAPR+ v2.7, and already use in by QEMU for generating powerdown
|
||||
requests via EPOW events.
|
||||
|
||||
For DR, this framework has been extended to include hotplug events, which were
|
||||
previously unneeded due to direct manipulation of DR-related guest userspace
|
||||
tools by host-level management such as an HMC. This level of management is not
|
||||
applicable to PowerKVM, hence the reason for extending the notification
|
||||
framework to support hotplug events.
|
||||
|
||||
The format for these EPOW-signalled events is described below under
|
||||
"hotplug/unplug event structure". Note that these events are not
|
||||
formally part of the PAPR+ specification, and have been superseded by a
|
||||
newer format, also described below under "hotplug/unplug event structure",
|
||||
and so are now deemed a "legacy" format. The formats are similar, but the
|
||||
"modern" format contains additional fields/flags, which are denoted for the
|
||||
purposes of this documentation with "#ifdef GUEST_SUPPORTS_MODERN" guards.
|
||||
|
||||
QEMU should assume support only for "legacy" fields/flags unless the guest
|
||||
advertises support for the "modern" format via ibm,client-architecture-support
|
||||
hcall by setting byte 5, bit 6 of it's ibm,architecture-vec-5 option vector
|
||||
structure (as described by LoPAPR v11, B.6.2.3). As with "legacy" format events,
|
||||
"modern" format events are surfaced to the guest via check-exception RTAS calls,
|
||||
but use a dedicated event source to signal the guest. This event source is
|
||||
advertised to the guest by the addition of a "hot-plug-events" node under
|
||||
"/event-sources" node of the guest's device tree using the standard format
|
||||
described in LoPAPR v11, B.6.12.1.
|
||||
|
||||
== hotplug/unplug event structure ==
|
||||
|
||||
The hotplug-specific payload in QEMU is implemented as follows (with all values
|
||||
encoded in big-endian format):
|
||||
|
||||
struct rtas_event_log_v6_hp {
|
||||
#define SECTION_ID_HOTPLUG 0x4850 /* HP */
|
||||
struct section_header {
|
||||
uint16_t section_id; /* set to SECTION_ID_HOTPLUG */
|
||||
uint16_t section_length; /* sizeof(rtas_event_log_v6_hp),
|
||||
* plus the length of the DRC name
|
||||
* if a DRC name identifier is
|
||||
* specified for hotplug_identifier
|
||||
*/
|
||||
uint8_t section_version; /* version 1 */
|
||||
uint8_t section_subtype; /* unused */
|
||||
uint16_t creator_component_id; /* unused */
|
||||
} hdr;
|
||||
#define RTAS_LOG_V6_HP_TYPE_CPU 1
|
||||
#define RTAS_LOG_V6_HP_TYPE_MEMORY 2
|
||||
#define RTAS_LOG_V6_HP_TYPE_SLOT 3
|
||||
#define RTAS_LOG_V6_HP_TYPE_PHB 4
|
||||
#define RTAS_LOG_V6_HP_TYPE_PCI 5
|
||||
uint8_t hotplug_type; /* type of resource/device */
|
||||
#define RTAS_LOG_V6_HP_ACTION_ADD 1
|
||||
#define RTAS_LOG_V6_HP_ACTION_REMOVE 2
|
||||
uint8_t hotplug_action; /* action (add/remove) */
|
||||
#define RTAS_LOG_V6_HP_ID_DRC_NAME 1
|
||||
#define RTAS_LOG_V6_HP_ID_DRC_INDEX 2
|
||||
#define RTAS_LOG_V6_HP_ID_DRC_COUNT 3
|
||||
#ifdef GUEST_SUPPORTS_MODERN
|
||||
#define RTAS_LOG_V6_HP_ID_DRC_COUNT_INDEXED 4
|
||||
#endif
|
||||
uint8_t hotplug_identifier; /* type of the resource identifier,
|
||||
* which serves as the discriminator
|
||||
* for the 'drc' union field below
|
||||
*/
|
||||
#ifdef GUEST_SUPPORTS_MODERN
|
||||
uint8_t capabilities; /* capability flags, currently unused
|
||||
* by QEMU
|
||||
*/
|
||||
#else
|
||||
uint8_t reserved;
|
||||
#endif
|
||||
union {
|
||||
uint32_t index; /* DRC index of resource to take action
|
||||
* on
|
||||
*/
|
||||
uint32_t count; /* number of DR resources to take
|
||||
* action on (guest chooses which)
|
||||
*/
|
||||
#ifdef GUEST_SUPPORTS_MODERN
|
||||
struct {
|
||||
uint32_t count; /* number of DR resources to take
|
||||
* action on
|
||||
*/
|
||||
uint32_t index; /* DRC index of first resource to take
|
||||
* action on. guest will take action
|
||||
* on DRC index <index> through
|
||||
* DRC index <index + count - 1> in
|
||||
* sequential order
|
||||
*/
|
||||
} count_indexed;
|
||||
#endif
|
||||
char name[1]; /* string representing the name of the
|
||||
* DRC to take action on
|
||||
*/
|
||||
} drc;
|
||||
} QEMU_PACKED;
|
||||
|
||||
== ibm,lrdr-capacity ==
|
||||
|
||||
ibm,lrdr-capacity is a property in the /rtas device tree node that identifies
|
||||
the dynamic reconfiguration capabilities of the guest. It consists of a triple
|
||||
consisting of <phys>, <size> and <maxcpus>.
|
||||
|
||||
<phys>, encoded in BE format represents the maximum address in bytes and
|
||||
hence the maximum memory that can be allocated to the guest.
|
||||
|
||||
<size>, encoded in BE format represents the size increments in which
|
||||
memory can be hot-plugged to the guest.
|
||||
|
||||
<maxcpus>, a BE-encoded integer, represents the maximum number of
|
||||
processors that the guest can have.
|
||||
|
||||
pseries guests use this property to note the maximum allowed CPUs for the
|
||||
guest.
|
||||
|
||||
== ibm,dynamic-reconfiguration-memory ==
|
||||
|
||||
ibm,dynamic-reconfiguration-memory is a device tree node that represents
|
||||
dynamically reconfigurable logical memory blocks (LMB). This node
|
||||
is generated only when the guest advertises the support for it via
|
||||
ibm,client-architecture-support call. Memory that is not dynamically
|
||||
reconfigurable is represented by /memory nodes. The properties of this
|
||||
node that are of interest to the sPAPR memory hotplug implementation
|
||||
in QEMU are described here.
|
||||
|
||||
ibm,lmb-size
|
||||
|
||||
This 64bit integer defines the size of each dynamically reconfigurable LMB.
|
||||
|
||||
ibm,associativity-lookup-arrays
|
||||
|
||||
This property defines a lookup array in which the NUMA associativity
|
||||
information for each LMB can be found. It is a property encoded array
|
||||
that begins with an integer M, the number of associativity lists followed
|
||||
by an integer N, the number of entries per associativity list and terminated
|
||||
by M associativity lists each of length N integers.
|
||||
|
||||
This property provides the same information as given by ibm,associativity
|
||||
property in a /memory node. Each assigned LMB has an index value between
|
||||
0 and M-1 which is used as an index into this table to select which
|
||||
associativity list to use for the LMB. This index value for each LMB
|
||||
is defined in ibm,dynamic-memory property.
|
||||
|
||||
ibm,dynamic-memory
|
||||
|
||||
This property describes the dynamically reconfigurable memory. It is a
|
||||
property encoded array that has an integer N, the number of LMBs followed
|
||||
by N LMB list entries.
|
||||
|
||||
Each LMB list entry consists of the following elements:
|
||||
|
||||
- Logical address of the start of the LMB encoded as a 64bit integer. This
|
||||
corresponds to reg property in /memory node.
|
||||
- DRC index of the LMB that corresponds to ibm,my-drc-index property
|
||||
in a /memory node.
|
||||
- Four bytes reserved for expansion.
|
||||
- Associativity list index for the LMB that is used as an index into
|
||||
ibm,associativity-lookup-arrays property described earlier. This
|
||||
is used to retrieve the right associativity list to be used for this
|
||||
LMB.
|
||||
- A 32bit flags word. The bit at bit position 0x00000008 defines whether
|
||||
the LMB is assigned to the partition as of boot time.
|
||||
|
||||
ibm,dynamic-memory-v2
|
||||
|
||||
This property describes the dynamically reconfigurable memory. This is
|
||||
an alternate and newer way to describe dynamically reconfigurable memory.
|
||||
It is a property encoded array that has an integer N (the number of
|
||||
LMB set entries) followed by N LMB set entries. There is an LMB set entry
|
||||
for each sequential group of LMBs that share common attributes.
|
||||
|
||||
Each LMB set entry consists of the following elements:
|
||||
|
||||
- Number of sequential LMBs in the entry represented by a 32bit integer.
|
||||
- Logical address of the first LMB in the set encoded as a 64bit integer.
|
||||
- DRC index of the first LMB in the set.
|
||||
- Associativity list index that is used as an index into
|
||||
ibm,associativity-lookup-arrays property described earlier. This
|
||||
is used to retrieve the right associativity list to be used for all
|
||||
the LMBs in this set.
|
||||
- A 32bit flags word that applies to all the LMBs in the set.
|
||||
|
||||
[1] http://thread.gmane.org/gmane.linux.ports.ppc.embedded/75350/focus=106867
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user