Compare commits
74 Commits
v8.2.1
...
tdx-qemu-u
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d20f93da31 | ||
|
|
18f152401f | ||
|
|
5c8d76a6e4 | ||
|
|
f226ab5a34 | ||
|
|
e954cd4b22 | ||
|
|
2dbde0df24 | ||
|
|
9faa2b03a9 | ||
|
|
d04ea558aa | ||
|
|
378e61b145 | ||
|
|
fdd53e1a81 | ||
|
|
e1ce29aa33 | ||
|
|
ffe9a6dccb | ||
|
|
7163da7797 | ||
|
|
a5368c6202 | ||
|
|
f597afe309 | ||
|
|
a23e29229e | ||
|
|
addb6b676d | ||
|
|
824f58fdba | ||
|
|
9955e91601 | ||
|
|
80417c539e | ||
|
|
511b09205f | ||
|
|
85a8152691 | ||
|
|
08c095f67a | ||
|
|
d8da77238e | ||
|
|
ab857b85a5 | ||
|
|
517fb00637 | ||
|
|
359be44b10 | ||
|
|
0222b6f05d | ||
|
|
8b7763f7ca | ||
|
|
33edcc8426 | ||
|
|
19195c88df | ||
|
|
954b9e7a42 | ||
|
|
5aad9329d2 | ||
|
|
583aae3302 | ||
|
|
80af3f2547 | ||
|
|
ef90193248 | ||
|
|
769b8158f6 | ||
|
|
d7db7d2ea1 | ||
|
|
004db71f60 | ||
|
|
bbe50409ce | ||
|
|
2ac24a3f82 | ||
|
|
7671a8d293 | ||
|
|
5bf04c14d8 | ||
|
|
f503878704 | ||
|
|
98f599ec0b | ||
|
|
a1b994d89a | ||
|
|
04fc588ea9 | ||
|
|
7e454d2ca4 | ||
|
|
b4a0470949 | ||
|
|
5fdefc08b3 | ||
|
|
d54122cefb | ||
|
|
ef64621235 | ||
|
|
575bfcd358 | ||
|
|
38b04243ce | ||
|
|
c64b4c4e28 | ||
|
|
871c9f21ee | ||
|
|
3770c1f6cb | ||
|
|
636758fe40 | ||
|
|
c9636b4bf5 | ||
|
|
d39ad1ccfd | ||
|
|
552a4e57a8 | ||
|
|
105fa48cab | ||
|
|
9824769418 | ||
|
|
02fda3dd28 | ||
|
|
609e0ca1d8 | ||
|
|
d21132fe6e | ||
|
|
902dc0c4a7 | ||
|
|
7bd3bf6642 | ||
|
|
843bbbd03b | ||
|
|
3091ad45a5 | ||
|
|
8d635c6681 | ||
|
|
f5fd218755 | ||
|
|
d5591ff440 | ||
|
|
605d572f9c |
@@ -41,7 +41,7 @@ build-system-ubuntu:
|
|||||||
variables:
|
variables:
|
||||||
IMAGE: ubuntu2204
|
IMAGE: ubuntu2204
|
||||||
CONFIGURE_ARGS: --enable-docs
|
CONFIGURE_ARGS: --enable-docs
|
||||||
TARGETS: alpha-softmmu microblaze-softmmu mips64el-softmmu
|
TARGETS: alpha-softmmu microblazeel-softmmu mips64el-softmmu
|
||||||
MAKE_CHECK_ARGS: check-build
|
MAKE_CHECK_ARGS: check-build
|
||||||
|
|
||||||
check-system-ubuntu:
|
check-system-ubuntu:
|
||||||
@@ -70,7 +70,7 @@ build-system-debian:
|
|||||||
needs:
|
needs:
|
||||||
job: amd64-debian-container
|
job: amd64-debian-container
|
||||||
variables:
|
variables:
|
||||||
IMAGE: debian
|
IMAGE: debian-amd64
|
||||||
CONFIGURE_ARGS: --with-coroutine=sigaltstack
|
CONFIGURE_ARGS: --with-coroutine=sigaltstack
|
||||||
TARGETS: arm-softmmu i386-softmmu riscv64-softmmu sh4eb-softmmu
|
TARGETS: arm-softmmu i386-softmmu riscv64-softmmu sh4eb-softmmu
|
||||||
sparc-softmmu xtensa-softmmu
|
sparc-softmmu xtensa-softmmu
|
||||||
@@ -82,7 +82,7 @@ check-system-debian:
|
|||||||
- job: build-system-debian
|
- job: build-system-debian
|
||||||
artifacts: true
|
artifacts: true
|
||||||
variables:
|
variables:
|
||||||
IMAGE: debian
|
IMAGE: debian-amd64
|
||||||
MAKE_CHECK_ARGS: check
|
MAKE_CHECK_ARGS: check
|
||||||
|
|
||||||
avocado-system-debian:
|
avocado-system-debian:
|
||||||
@@ -91,7 +91,7 @@ avocado-system-debian:
|
|||||||
- job: build-system-debian
|
- job: build-system-debian
|
||||||
artifacts: true
|
artifacts: true
|
||||||
variables:
|
variables:
|
||||||
IMAGE: debian
|
IMAGE: debian-amd64
|
||||||
MAKE_CHECK_ARGS: check-avocado
|
MAKE_CHECK_ARGS: check-avocado
|
||||||
AVOCADO_TAGS: arch:arm arch:i386 arch:riscv64 arch:sh4 arch:sparc arch:xtensa
|
AVOCADO_TAGS: arch:arm arch:i386 arch:riscv64 arch:sh4 arch:sparc arch:xtensa
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ crash-test-debian:
|
|||||||
- job: build-system-debian
|
- job: build-system-debian
|
||||||
artifacts: true
|
artifacts: true
|
||||||
variables:
|
variables:
|
||||||
IMAGE: debian
|
IMAGE: debian-amd64
|
||||||
script:
|
script:
|
||||||
- cd build
|
- cd build
|
||||||
- make NINJA=":" check-venv
|
- make NINJA=":" check-venv
|
||||||
@@ -217,36 +217,6 @@ avocado-system-opensuse:
|
|||||||
MAKE_CHECK_ARGS: check-avocado
|
MAKE_CHECK_ARGS: check-avocado
|
||||||
AVOCADO_TAGS: arch:s390x arch:x86_64 arch:aarch64
|
AVOCADO_TAGS: arch:s390x arch:x86_64 arch:aarch64
|
||||||
|
|
||||||
#
|
|
||||||
# Flaky tests. We don't run these by default and they are allow fail
|
|
||||||
# but often the CI system is the only way to trigger the failures.
|
|
||||||
#
|
|
||||||
|
|
||||||
build-system-flaky:
|
|
||||||
extends:
|
|
||||||
- .native_build_job_template
|
|
||||||
- .native_build_artifact_template
|
|
||||||
needs:
|
|
||||||
job: amd64-debian-container
|
|
||||||
variables:
|
|
||||||
IMAGE: debian
|
|
||||||
QEMU_JOB_OPTIONAL: 1
|
|
||||||
TARGETS: aarch64-softmmu arm-softmmu mips64el-softmmu
|
|
||||||
ppc64-softmmu rx-softmmu s390x-softmmu sh4-softmmu x86_64-softmmu
|
|
||||||
MAKE_CHECK_ARGS: check-build
|
|
||||||
|
|
||||||
avocado-system-flaky:
|
|
||||||
extends: .avocado_test_job_template
|
|
||||||
needs:
|
|
||||||
- job: build-system-flaky
|
|
||||||
artifacts: true
|
|
||||||
allow_failure: true
|
|
||||||
variables:
|
|
||||||
IMAGE: debian
|
|
||||||
MAKE_CHECK_ARGS: check-avocado
|
|
||||||
QEMU_JOB_OPTIONAL: 1
|
|
||||||
QEMU_TEST_FLAKY_TESTS: 1
|
|
||||||
AVOCADO_TAGS: flaky
|
|
||||||
|
|
||||||
# This jobs explicitly disable TCG (--disable-tcg), KVM is detected by
|
# This jobs explicitly disable TCG (--disable-tcg), KVM is detected by
|
||||||
# the configure script. The container doesn't contain Xen headers so
|
# the configure script. The container doesn't contain Xen headers so
|
||||||
@@ -619,7 +589,7 @@ build-tools-and-docs-debian:
|
|||||||
# when running on 'master' we use pre-existing container
|
# when running on 'master' we use pre-existing container
|
||||||
optional: true
|
optional: true
|
||||||
variables:
|
variables:
|
||||||
IMAGE: debian
|
IMAGE: debian-amd64
|
||||||
MAKE_CHECK_ARGS: check-unit ctags TAGS cscope
|
MAKE_CHECK_ARGS: check-unit ctags TAGS cscope
|
||||||
CONFIGURE_ARGS: --disable-system --disable-user --enable-docs --enable-tools
|
CONFIGURE_ARGS: --disable-system --disable-user --enable-docs --enable-tools
|
||||||
QEMU_JOB_PUBLISH: 1
|
QEMU_JOB_PUBLISH: 1
|
||||||
@@ -639,7 +609,7 @@ build-tools-and-docs-debian:
|
|||||||
# of what topic branch they're currently using
|
# of what topic branch they're currently using
|
||||||
pages:
|
pages:
|
||||||
extends: .base_job_template
|
extends: .base_job_template
|
||||||
image: $CI_REGISTRY_IMAGE/qemu/debian:$QEMU_CI_CONTAINER_TAG
|
image: $CI_REGISTRY_IMAGE/qemu/debian-amd64:$QEMU_CI_CONTAINER_TAG
|
||||||
stage: test
|
stage: test
|
||||||
needs:
|
needs:
|
||||||
- job: build-tools-and-docs-debian
|
- job: build-tools-and-docs-debian
|
||||||
@@ -647,10 +617,7 @@ pages:
|
|||||||
- mkdir -p public
|
- mkdir -p public
|
||||||
# HTML-ised source tree
|
# HTML-ised source tree
|
||||||
- make gtags
|
- make gtags
|
||||||
# We unset variables to work around a bug in some htags versions
|
- htags -anT --tree-view=filetree -m qemu_init
|
||||||
# which causes it to fail when the environment is large
|
|
||||||
- CI_COMMIT_MESSAGE= CI_COMMIT_TAG_MESSAGE= htags
|
|
||||||
-anT --tree-view=filetree -m qemu_init
|
|
||||||
-t "Welcome to the QEMU sourcecode"
|
-t "Welcome to the QEMU sourcecode"
|
||||||
- mv HTML public/src
|
- mv HTML public/src
|
||||||
# Project documentation
|
# Project documentation
|
||||||
|
|||||||
@@ -59,13 +59,13 @@ x64-freebsd-13-build:
|
|||||||
INSTALL_COMMAND: pkg install -y
|
INSTALL_COMMAND: pkg install -y
|
||||||
TEST_TARGETS: check
|
TEST_TARGETS: check
|
||||||
|
|
||||||
aarch64-macos-13-base-build:
|
aarch64-macos-12-base-build:
|
||||||
extends: .cirrus_build_job
|
extends: .cirrus_build_job
|
||||||
variables:
|
variables:
|
||||||
NAME: macos-13
|
NAME: macos-12
|
||||||
CIRRUS_VM_INSTANCE_TYPE: macos_instance
|
CIRRUS_VM_INSTANCE_TYPE: macos_instance
|
||||||
CIRRUS_VM_IMAGE_SELECTOR: image
|
CIRRUS_VM_IMAGE_SELECTOR: image
|
||||||
CIRRUS_VM_IMAGE_NAME: ghcr.io/cirruslabs/macos-ventura-base:latest
|
CIRRUS_VM_IMAGE_NAME: ghcr.io/cirruslabs/macos-monterey-base:latest
|
||||||
CIRRUS_VM_CPUS: 12
|
CIRRUS_VM_CPUS: 12
|
||||||
CIRRUS_VM_RAM: 24G
|
CIRRUS_VM_RAM: 24G
|
||||||
UPDATE_COMMAND: brew update
|
UPDATE_COMMAND: brew update
|
||||||
@@ -74,22 +74,6 @@ aarch64-macos-13-base-build:
|
|||||||
PKG_CONFIG_PATH: /opt/homebrew/curl/lib/pkgconfig:/opt/homebrew/ncurses/lib/pkgconfig:/opt/homebrew/readline/lib/pkgconfig
|
PKG_CONFIG_PATH: /opt/homebrew/curl/lib/pkgconfig:/opt/homebrew/ncurses/lib/pkgconfig:/opt/homebrew/readline/lib/pkgconfig
|
||||||
TEST_TARGETS: check-unit check-block check-qapi-schema check-softfloat check-qtest-x86_64
|
TEST_TARGETS: check-unit check-block check-qapi-schema check-softfloat check-qtest-x86_64
|
||||||
|
|
||||||
aarch64-macos-14-base-build:
|
|
||||||
extends: .cirrus_build_job
|
|
||||||
variables:
|
|
||||||
NAME: macos-14
|
|
||||||
CIRRUS_VM_INSTANCE_TYPE: macos_instance
|
|
||||||
CIRRUS_VM_IMAGE_SELECTOR: image
|
|
||||||
CIRRUS_VM_IMAGE_NAME: ghcr.io/cirruslabs/macos-sonoma-base:latest
|
|
||||||
CIRRUS_VM_CPUS: 12
|
|
||||||
CIRRUS_VM_RAM: 24G
|
|
||||||
UPDATE_COMMAND: brew update
|
|
||||||
INSTALL_COMMAND: brew install
|
|
||||||
PATH_EXTRA: /opt/homebrew/ccache/libexec:/opt/homebrew/gettext/bin
|
|
||||||
PKG_CONFIG_PATH: /opt/homebrew/curl/lib/pkgconfig:/opt/homebrew/ncurses/lib/pkgconfig:/opt/homebrew/readline/lib/pkgconfig
|
|
||||||
TEST_TARGETS: check-unit check-block check-qapi-schema check-softfloat check-qtest-x86_64
|
|
||||||
QEMU_JOB_OPTIONAL: 1
|
|
||||||
|
|
||||||
|
|
||||||
# The following jobs run VM-based tests via KVM on a Linux-based Cirrus-CI job
|
# The following jobs run VM-based tests via KVM on a Linux-based Cirrus-CI job
|
||||||
.cirrus_kvm_job:
|
.cirrus_kvm_job:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# THIS FILE WAS AUTO-GENERATED
|
# THIS FILE WAS AUTO-GENERATED
|
||||||
#
|
#
|
||||||
# $ lcitool variables macos-13 qemu
|
# $ lcitool variables macos-12 qemu
|
||||||
#
|
#
|
||||||
# https://gitlab.com/libvirt/libvirt-ci
|
# https://gitlab.com/libvirt/libvirt-ci
|
||||||
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
# THIS FILE WAS AUTO-GENERATED
|
|
||||||
#
|
|
||||||
# $ lcitool variables macos-14 qemu
|
|
||||||
#
|
|
||||||
# https://gitlab.com/libvirt/libvirt-ci
|
|
||||||
|
|
||||||
CCACHE='/opt/homebrew/bin/ccache'
|
|
||||||
CPAN_PKGS=''
|
|
||||||
CROSS_PKGS=''
|
|
||||||
MAKE='/opt/homebrew/bin/gmake'
|
|
||||||
NINJA='/opt/homebrew/bin/ninja'
|
|
||||||
PACKAGING_COMMAND='brew'
|
|
||||||
PIP3='/opt/homebrew/bin/pip3'
|
|
||||||
PKGS='bash bc bison bzip2 capstone ccache cmocka ctags curl dbus diffutils dtc flex gcovr gettext git glib gnu-sed gnutls gtk+3 jemalloc jpeg-turbo json-c libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make meson mtools ncurses nettle ninja pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy socat sparse spice-protocol swtpm tesseract usbredir vde vte3 xorriso zlib zstd'
|
|
||||||
PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme tomli'
|
|
||||||
PYTHON='/opt/homebrew/bin/python3'
|
|
||||||
@@ -46,12 +46,6 @@ loongarch-debian-cross-container:
|
|||||||
variables:
|
variables:
|
||||||
NAME: debian-loongarch-cross
|
NAME: debian-loongarch-cross
|
||||||
|
|
||||||
i686-debian-cross-container:
|
|
||||||
extends: .container_job_template
|
|
||||||
stage: containers
|
|
||||||
variables:
|
|
||||||
NAME: debian-i686-cross
|
|
||||||
|
|
||||||
mips64el-debian-cross-container:
|
mips64el-debian-cross-container:
|
||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
stage: containers
|
stage: containers
|
||||||
@@ -101,6 +95,11 @@ cris-fedora-cross-container:
|
|||||||
variables:
|
variables:
|
||||||
NAME: fedora-cris-cross
|
NAME: fedora-cris-cross
|
||||||
|
|
||||||
|
i386-fedora-cross-container:
|
||||||
|
extends: .container_job_template
|
||||||
|
variables:
|
||||||
|
NAME: fedora-i386-cross
|
||||||
|
|
||||||
win32-fedora-cross-container:
|
win32-fedora-cross-container:
|
||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
variables:
|
variables:
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ amd64-debian-container:
|
|||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
stage: containers
|
stage: containers
|
||||||
variables:
|
variables:
|
||||||
NAME: debian
|
NAME: debian-amd64
|
||||||
|
|
||||||
amd64-ubuntu2204-container:
|
amd64-ubuntu2204-container:
|
||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
|
|||||||
@@ -37,25 +37,25 @@ cross-arm64-kvm-only:
|
|||||||
IMAGE: debian-arm64-cross
|
IMAGE: debian-arm64-cross
|
||||||
EXTRA_CONFIGURE_OPTS: --disable-tcg --without-default-features
|
EXTRA_CONFIGURE_OPTS: --disable-tcg --without-default-features
|
||||||
|
|
||||||
cross-i686-user:
|
cross-i386-user:
|
||||||
extends:
|
extends:
|
||||||
- .cross_user_build_job
|
- .cross_user_build_job
|
||||||
- .cross_test_artifacts
|
- .cross_test_artifacts
|
||||||
needs:
|
needs:
|
||||||
job: i686-debian-cross-container
|
job: i386-fedora-cross-container
|
||||||
variables:
|
variables:
|
||||||
IMAGE: debian-i686-cross
|
IMAGE: fedora-i386-cross
|
||||||
MAKE_CHECK_ARGS: check
|
MAKE_CHECK_ARGS: check
|
||||||
|
|
||||||
cross-i686-tci:
|
cross-i386-tci:
|
||||||
extends:
|
extends:
|
||||||
- .cross_accel_build_job
|
- .cross_accel_build_job
|
||||||
- .cross_test_artifacts
|
- .cross_test_artifacts
|
||||||
timeout: 60m
|
timeout: 60m
|
||||||
needs:
|
needs:
|
||||||
job: i686-debian-cross-container
|
job: i386-fedora-cross-container
|
||||||
variables:
|
variables:
|
||||||
IMAGE: debian-i686-cross
|
IMAGE: fedora-i386-cross
|
||||||
ACCEL: tcg-interpreter
|
ACCEL: tcg-interpreter
|
||||||
EXTRA_CONFIGURE_OPTS: --target-list=i386-softmmu,i386-linux-user,aarch64-softmmu,aarch64-linux-user,ppc-softmmu,ppc-linux-user --disable-plugins
|
EXTRA_CONFIGURE_OPTS: --target-list=i386-softmmu,i386-linux-user,aarch64-softmmu,aarch64-linux-user,ppc-softmmu,ppc-linux-user --disable-plugins
|
||||||
MAKE_CHECK_ARGS: check check-tcg
|
MAKE_CHECK_ARGS: check check-tcg
|
||||||
@@ -165,7 +165,7 @@ cross-win32-system:
|
|||||||
job: win32-fedora-cross-container
|
job: win32-fedora-cross-container
|
||||||
variables:
|
variables:
|
||||||
IMAGE: fedora-win32-cross
|
IMAGE: fedora-win32-cross
|
||||||
EXTRA_CONFIGURE_OPTS: --enable-fdt=internal
|
EXTRA_CONFIGURE_OPTS: --enable-fdt=internal --disable-plugins
|
||||||
CROSS_SKIP_TARGETS: alpha-softmmu avr-softmmu hppa-softmmu m68k-softmmu
|
CROSS_SKIP_TARGETS: alpha-softmmu avr-softmmu hppa-softmmu m68k-softmmu
|
||||||
microblazeel-softmmu mips64el-softmmu nios2-softmmu
|
microblazeel-softmmu mips64el-softmmu nios2-softmmu
|
||||||
artifacts:
|
artifacts:
|
||||||
|
|||||||
@@ -5,21 +5,16 @@
|
|||||||
# Required
|
# Required
|
||||||
version: 2
|
version: 2
|
||||||
|
|
||||||
# Set the version of Python and other tools you might need
|
|
||||||
build:
|
|
||||||
os: ubuntu-22.04
|
|
||||||
tools:
|
|
||||||
python: "3.11"
|
|
||||||
|
|
||||||
# Build documentation in the docs/ directory with Sphinx
|
# Build documentation in the docs/ directory with Sphinx
|
||||||
sphinx:
|
sphinx:
|
||||||
configuration: docs/conf.py
|
configuration: docs/conf.py
|
||||||
|
|
||||||
# We recommend specifying your dependencies to enable reproducible builds:
|
|
||||||
# https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
|
|
||||||
python:
|
|
||||||
install:
|
|
||||||
- requirements: docs/requirements.txt
|
|
||||||
|
|
||||||
# We want all the document formats
|
# We want all the document formats
|
||||||
formats: all
|
formats: all
|
||||||
|
|
||||||
|
# For consistency, we require that QEMU's Sphinx extensions
|
||||||
|
# run with at least the same minimum version of Python that
|
||||||
|
# we require for other Python in our codebase (our conf.py
|
||||||
|
# enforces this, and some code needs it.)
|
||||||
|
python:
|
||||||
|
version: 3.6
|
||||||
|
|||||||
@@ -174,7 +174,6 @@ F: include/hw/core/tcg-cpu-ops.h
|
|||||||
F: host/include/*/host/cpuinfo.h
|
F: host/include/*/host/cpuinfo.h
|
||||||
F: util/cpuinfo-*.c
|
F: util/cpuinfo-*.c
|
||||||
F: include/tcg/
|
F: include/tcg/
|
||||||
F: tests/decode/
|
|
||||||
|
|
||||||
FPU emulation
|
FPU emulation
|
||||||
M: Aurelien Jarno <aurelien@aurel32.net>
|
M: Aurelien Jarno <aurelien@aurel32.net>
|
||||||
|
|||||||
@@ -101,6 +101,8 @@ bool kvm_msi_use_devid;
|
|||||||
bool kvm_has_guest_debug;
|
bool kvm_has_guest_debug;
|
||||||
static int kvm_sstep_flags;
|
static int kvm_sstep_flags;
|
||||||
static bool kvm_immediate_exit;
|
static bool kvm_immediate_exit;
|
||||||
|
static bool kvm_guest_memfd_supported;
|
||||||
|
static uint64_t kvm_supported_memory_attributes;
|
||||||
static hwaddr kvm_max_slot_size = ~0;
|
static hwaddr kvm_max_slot_size = ~0;
|
||||||
|
|
||||||
static const KVMCapabilityInfo kvm_required_capabilites[] = {
|
static const KVMCapabilityInfo kvm_required_capabilites[] = {
|
||||||
@@ -292,35 +294,70 @@ int kvm_physical_memory_addr_from_host(KVMState *s, void *ram,
|
|||||||
static int kvm_set_user_memory_region(KVMMemoryListener *kml, KVMSlot *slot, bool new)
|
static int kvm_set_user_memory_region(KVMMemoryListener *kml, KVMSlot *slot, bool new)
|
||||||
{
|
{
|
||||||
KVMState *s = kvm_state;
|
KVMState *s = kvm_state;
|
||||||
struct kvm_userspace_memory_region mem;
|
struct kvm_userspace_memory_region2 mem;
|
||||||
|
static int cap_user_memory2 = -1;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (cap_user_memory2 == -1) {
|
||||||
|
cap_user_memory2 = kvm_check_extension(s, KVM_CAP_USER_MEMORY2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cap_user_memory2 && slot->guest_memfd >= 0) {
|
||||||
|
error_report("%s, KVM doesn't support KVM_CAP_USER_MEMORY2,"
|
||||||
|
" which is required by guest memfd!", __func__);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
mem.slot = slot->slot | (kml->as_id << 16);
|
mem.slot = slot->slot | (kml->as_id << 16);
|
||||||
mem.guest_phys_addr = slot->start_addr;
|
mem.guest_phys_addr = slot->start_addr;
|
||||||
mem.userspace_addr = (unsigned long)slot->ram;
|
mem.userspace_addr = (unsigned long)slot->ram;
|
||||||
mem.flags = slot->flags;
|
mem.flags = slot->flags;
|
||||||
|
mem.guest_memfd = slot->guest_memfd;
|
||||||
|
mem.guest_memfd_offset = slot->guest_memfd_offset;
|
||||||
|
|
||||||
if (slot->memory_size && !new && (mem.flags ^ slot->old_flags) & KVM_MEM_READONLY) {
|
if (slot->memory_size && !new && (mem.flags ^ slot->old_flags) & KVM_MEM_READONLY) {
|
||||||
/* Set the slot size to 0 before setting the slot to the desired
|
/* Set the slot size to 0 before setting the slot to the desired
|
||||||
* value. This is needed based on KVM commit 75d61fbc. */
|
* value. This is needed based on KVM commit 75d61fbc. */
|
||||||
mem.memory_size = 0;
|
mem.memory_size = 0;
|
||||||
|
|
||||||
|
if (cap_user_memory2) {
|
||||||
|
ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION2, &mem);
|
||||||
|
} else {
|
||||||
ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
|
ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
|
||||||
|
}
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mem.memory_size = slot->memory_size;
|
mem.memory_size = slot->memory_size;
|
||||||
|
if (cap_user_memory2) {
|
||||||
|
ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION2, &mem);
|
||||||
|
} else {
|
||||||
ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
|
ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
|
||||||
|
}
|
||||||
slot->old_flags = mem.flags;
|
slot->old_flags = mem.flags;
|
||||||
err:
|
err:
|
||||||
trace_kvm_set_user_memory(mem.slot, mem.flags, mem.guest_phys_addr,
|
trace_kvm_set_user_memory(mem.slot >> 16, (uint16_t)mem.slot, mem.flags,
|
||||||
mem.memory_size, mem.userspace_addr, ret);
|
mem.guest_phys_addr, mem.memory_size,
|
||||||
|
mem.userspace_addr, mem.guest_memfd,
|
||||||
|
mem.guest_memfd_offset, ret);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
if (cap_user_memory2) {
|
||||||
|
error_report("%s: KVM_SET_USER_MEMORY_REGION2 failed, slot=%d,"
|
||||||
|
" start=0x%" PRIx64 ", size=0x%" PRIx64 ","
|
||||||
|
" flags=0x%" PRIx32 ", guest_memfd=%" PRId32 ","
|
||||||
|
" guest_memfd_offset=0x%" PRIx64 ": %s",
|
||||||
|
__func__, mem.slot, slot->start_addr,
|
||||||
|
(uint64_t)mem.memory_size, mem.flags,
|
||||||
|
mem.guest_memfd, (uint64_t)mem.guest_memfd_offset,
|
||||||
|
strerror(errno));
|
||||||
|
} else {
|
||||||
error_report("%s: KVM_SET_USER_MEMORY_REGION failed, slot=%d,"
|
error_report("%s: KVM_SET_USER_MEMORY_REGION failed, slot=%d,"
|
||||||
" start=0x%" PRIx64 ", size=0x%" PRIx64 ": %s",
|
" start=0x%" PRIx64 ", size=0x%" PRIx64 ": %s",
|
||||||
__func__, mem.slot, slot->start_addr,
|
__func__, mem.slot, slot->start_addr,
|
||||||
(uint64_t)mem.memory_size, strerror(errno));
|
(uint64_t)mem.memory_size, strerror(errno));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,6 +428,11 @@ static int kvm_get_vcpu(KVMState *s, unsigned long vcpu_id)
|
|||||||
return kvm_vm_ioctl(s, KVM_CREATE_VCPU, (void *)vcpu_id);
|
return kvm_vm_ioctl(s, KVM_CREATE_VCPU, (void *)vcpu_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int __attribute__ ((weak)) kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int kvm_init_vcpu(CPUState *cpu, Error **errp)
|
int kvm_init_vcpu(CPUState *cpu, Error **errp)
|
||||||
{
|
{
|
||||||
KVMState *s = kvm_state;
|
KVMState *s = kvm_state;
|
||||||
@@ -399,15 +441,27 @@ int kvm_init_vcpu(CPUState *cpu, Error **errp)
|
|||||||
|
|
||||||
trace_kvm_init_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu));
|
trace_kvm_init_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* tdx_pre_create_vcpu() may call cpu_x86_cpuid(). It in turn may call
|
||||||
|
* kvm_vm_ioctl(). Set cpu->kvm_state in advance to avoid NULL pointer
|
||||||
|
* dereference.
|
||||||
|
*/
|
||||||
|
cpu->kvm_state = s;
|
||||||
|
ret = kvm_arch_pre_create_vcpu(cpu, errp);
|
||||||
|
if (ret < 0) {
|
||||||
|
cpu->kvm_state = NULL;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
ret = kvm_get_vcpu(s, kvm_arch_vcpu_id(cpu));
|
ret = kvm_get_vcpu(s, kvm_arch_vcpu_id(cpu));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg_errno(errp, -ret, "kvm_init_vcpu: kvm_get_vcpu failed (%lu)",
|
error_setg_errno(errp, -ret, "kvm_init_vcpu: kvm_get_vcpu failed (%lu)",
|
||||||
kvm_arch_vcpu_id(cpu));
|
kvm_arch_vcpu_id(cpu));
|
||||||
|
cpu->kvm_state = NULL;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu->kvm_fd = ret;
|
cpu->kvm_fd = ret;
|
||||||
cpu->kvm_state = s;
|
|
||||||
cpu->vcpu_dirty = true;
|
cpu->vcpu_dirty = true;
|
||||||
cpu->dirty_pages = 0;
|
cpu->dirty_pages = 0;
|
||||||
cpu->throttle_us_per_full = 0;
|
cpu->throttle_us_per_full = 0;
|
||||||
@@ -475,6 +529,9 @@ static int kvm_mem_flags(MemoryRegion *mr)
|
|||||||
if (readonly && kvm_readonly_mem_allowed) {
|
if (readonly && kvm_readonly_mem_allowed) {
|
||||||
flags |= KVM_MEM_READONLY;
|
flags |= KVM_MEM_READONLY;
|
||||||
}
|
}
|
||||||
|
if (memory_region_has_guest_memfd(mr)) {
|
||||||
|
flags |= KVM_MEM_PRIVATE;
|
||||||
|
}
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1266,6 +1323,44 @@ void kvm_set_max_memslot_size(hwaddr max_slot_size)
|
|||||||
kvm_max_slot_size = max_slot_size;
|
kvm_max_slot_size = max_slot_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int kvm_set_memory_attributes(hwaddr start, hwaddr size, uint64_t attr)
|
||||||
|
{
|
||||||
|
struct kvm_memory_attributes attrs;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
attrs.attributes = attr;
|
||||||
|
attrs.address = start;
|
||||||
|
attrs.size = size;
|
||||||
|
attrs.flags = 0;
|
||||||
|
|
||||||
|
r = kvm_vm_ioctl(kvm_state, KVM_SET_MEMORY_ATTRIBUTES, &attrs);
|
||||||
|
if (r) {
|
||||||
|
warn_report("%s: failed to set memory (0x%lx+%#zx) with attr 0x%lx error '%s'",
|
||||||
|
__func__, start, size, attr, strerror(errno));
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int kvm_set_memory_attributes_private(hwaddr start, hwaddr size)
|
||||||
|
{
|
||||||
|
if (!(kvm_supported_memory_attributes & KVM_MEMORY_ATTRIBUTE_PRIVATE)) {
|
||||||
|
error_report("KVM doesn't support PRIVATE memory attribute\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return kvm_set_memory_attributes(start, size, KVM_MEMORY_ATTRIBUTE_PRIVATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int kvm_set_memory_attributes_shared(hwaddr start, hwaddr size)
|
||||||
|
{
|
||||||
|
if (!(kvm_supported_memory_attributes & KVM_MEMORY_ATTRIBUTE_PRIVATE)) {
|
||||||
|
error_report("KVM doesn't support PRIVATE memory attribute\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return kvm_set_memory_attributes(start, size, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/* Called with KVMMemoryListener.slots_lock held */
|
/* Called with KVMMemoryListener.slots_lock held */
|
||||||
static void kvm_set_phys_mem(KVMMemoryListener *kml,
|
static void kvm_set_phys_mem(KVMMemoryListener *kml,
|
||||||
MemoryRegionSection *section, bool add)
|
MemoryRegionSection *section, bool add)
|
||||||
@@ -1362,6 +1457,9 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
|
|||||||
mem->ram_start_offset = ram_start_offset;
|
mem->ram_start_offset = ram_start_offset;
|
||||||
mem->ram = ram;
|
mem->ram = ram;
|
||||||
mem->flags = kvm_mem_flags(mr);
|
mem->flags = kvm_mem_flags(mr);
|
||||||
|
mem->guest_memfd = mr->ram_block->guest_memfd;
|
||||||
|
mem->guest_memfd_offset = (uint8_t*)ram - mr->ram_block->host;
|
||||||
|
|
||||||
kvm_slot_init_dirty_bitmap(mem);
|
kvm_slot_init_dirty_bitmap(mem);
|
||||||
err = kvm_set_user_memory_region(kml, mem, true);
|
err = kvm_set_user_memory_region(kml, mem, true);
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -1369,6 +1467,16 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
|
|||||||
strerror(-err));
|
strerror(-err));
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (memory_region_is_default_private(mr)) {
|
||||||
|
err = kvm_set_memory_attributes_private(start_addr, slot_size);
|
||||||
|
if (err) {
|
||||||
|
error_report("%s: failed to set memory attribute private: %s\n",
|
||||||
|
__func__, strerror(-err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
start_addr += slot_size;
|
start_addr += slot_size;
|
||||||
ram_start_offset += slot_size;
|
ram_start_offset += slot_size;
|
||||||
ram += slot_size;
|
ram += slot_size;
|
||||||
@@ -2396,6 +2504,11 @@ static int kvm_init(MachineState *ms)
|
|||||||
}
|
}
|
||||||
s->as = g_new0(struct KVMAs, s->nr_as);
|
s->as = g_new0(struct KVMAs, s->nr_as);
|
||||||
|
|
||||||
|
kvm_guest_memfd_supported = kvm_check_extension(s, KVM_CAP_GUEST_MEMFD);
|
||||||
|
|
||||||
|
ret = kvm_check_extension(s, KVM_CAP_MEMORY_ATTRIBUTES);
|
||||||
|
kvm_supported_memory_attributes = ret > 0 ? ret : 0;
|
||||||
|
|
||||||
if (object_property_find(OBJECT(current_machine), "kvm-type")) {
|
if (object_property_find(OBJECT(current_machine), "kvm-type")) {
|
||||||
g_autofree char *kvm_type = object_property_get_str(OBJECT(current_machine),
|
g_autofree char *kvm_type = object_property_get_str(OBJECT(current_machine),
|
||||||
"kvm-type",
|
"kvm-type",
|
||||||
@@ -2816,6 +2929,78 @@ static void kvm_eat_signals(CPUState *cpu)
|
|||||||
} while (sigismember(&chkset, SIG_IPI));
|
} while (sigismember(&chkset, SIG_IPI));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int kvm_convert_memory(hwaddr start, hwaddr size, bool to_private)
|
||||||
|
{
|
||||||
|
MemoryRegionSection section;
|
||||||
|
ram_addr_t offset;
|
||||||
|
MemoryRegion *mr;
|
||||||
|
RAMBlock *rb;
|
||||||
|
void *addr;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
trace_kvm_convert_memory(start, size, to_private ? "shared_to_private" : "private_to_shared");
|
||||||
|
section = memory_region_find(get_system_memory(), start, size);
|
||||||
|
mr = section.mr;
|
||||||
|
if (!mr) {
|
||||||
|
/*
|
||||||
|
* Ignore converting non-assigned region to shared.
|
||||||
|
*
|
||||||
|
* TDX requires vMMIO region to be shared to inject #VE to guest.
|
||||||
|
* OVMF issues conservatively MapGPA(shared) on 32bit PCI MMIO region,
|
||||||
|
* and vIO-APIC 0xFEC00000 4K page.
|
||||||
|
* OVMF assigns 32bit PCI MMIO region to
|
||||||
|
* [top of low memory: typically 2GB=0xC000000, 0xFC00000)
|
||||||
|
*/
|
||||||
|
if (!to_private) {
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memory_region_has_guest_memfd(mr)) {
|
||||||
|
if (to_private) {
|
||||||
|
ret = kvm_set_memory_attributes_private(start, size);
|
||||||
|
} else {
|
||||||
|
ret = kvm_set_memory_attributes_shared(start, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
memory_region_unref(section.mr);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr = memory_region_get_ram_ptr(section.mr) +
|
||||||
|
section.offset_within_region;
|
||||||
|
rb = qemu_ram_block_from_host(addr, false, &offset);
|
||||||
|
/*
|
||||||
|
* With KVM_SET_MEMORY_ATTRIBUTES by kvm_set_memory_attributes(),
|
||||||
|
* operation on underlying file descriptor is only for releasing
|
||||||
|
* unnecessary pages.
|
||||||
|
*/
|
||||||
|
ram_block_convert_range(rb, offset, size, to_private);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Because vMMIO region must be shared, guest TD may convert vMMIO
|
||||||
|
* region to shared explicitly. Don't complain such case. See
|
||||||
|
* memory_region_type() for checking if the region is MMIO region.
|
||||||
|
*/
|
||||||
|
if (!to_private &&
|
||||||
|
!memory_region_is_ram(mr) &&
|
||||||
|
!memory_region_is_ram_device(mr) &&
|
||||||
|
!memory_region_is_rom(mr) &&
|
||||||
|
!memory_region_is_romd(mr)) {
|
||||||
|
ret = 0;
|
||||||
|
} else {
|
||||||
|
warn_report("Convert non guest_memfd backed memory region "
|
||||||
|
"(0x%"HWADDR_PRIx" ,+ 0x%"HWADDR_PRIx") to %s",
|
||||||
|
start, size, to_private ? "private" : "shared");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memory_region_unref(section.mr);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int kvm_cpu_exec(CPUState *cpu)
|
int kvm_cpu_exec(CPUState *cpu)
|
||||||
{
|
{
|
||||||
struct kvm_run *run = cpu->kvm_run;
|
struct kvm_run *run = cpu->kvm_run;
|
||||||
@@ -2883,6 +3068,7 @@ int kvm_cpu_exec(CPUState *cpu)
|
|||||||
ret = EXCP_INTERRUPT;
|
ret = EXCP_INTERRUPT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (!(run_ret == -EFAULT && run->exit_reason == KVM_EXIT_MEMORY_FAULT)) {
|
||||||
fprintf(stderr, "error: kvm run failed %s\n",
|
fprintf(stderr, "error: kvm run failed %s\n",
|
||||||
strerror(-run_ret));
|
strerror(-run_ret));
|
||||||
#ifdef TARGET_PPC
|
#ifdef TARGET_PPC
|
||||||
@@ -2896,6 +3082,7 @@ int kvm_cpu_exec(CPUState *cpu)
|
|||||||
ret = -1;
|
ret = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
trace_kvm_run_exit(cpu->cpu_index, run->exit_reason);
|
trace_kvm_run_exit(cpu->cpu_index, run->exit_reason);
|
||||||
switch (run->exit_reason) {
|
switch (run->exit_reason) {
|
||||||
@@ -2981,6 +3168,16 @@ int kvm_cpu_exec(CPUState *cpu)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case KVM_EXIT_MEMORY_FAULT:
|
||||||
|
if (run->memory_fault.flags & ~KVM_MEMORY_EXIT_FLAG_PRIVATE) {
|
||||||
|
error_report("KVM_EXIT_MEMORY_FAULT: Unknown flag 0x%" PRIx64,
|
||||||
|
(uint64_t)run->memory_fault.flags);
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ret = kvm_convert_memory(run->memory_fault.gpa, run->memory_fault.size,
|
||||||
|
run->memory_fault.flags & KVM_MEMORY_EXIT_FLAG_PRIVATE);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
DPRINTF("kvm_arch_handle_exit\n");
|
DPRINTF("kvm_arch_handle_exit\n");
|
||||||
ret = kvm_arch_handle_exit(cpu, run);
|
ret = kvm_arch_handle_exit(cpu, run);
|
||||||
@@ -4077,3 +4274,24 @@ void query_stats_schemas_cb(StatsSchemaList **result, Error **errp)
|
|||||||
query_stats_schema_vcpu(first_cpu, &stats_args);
|
query_stats_schema_vcpu(first_cpu, &stats_args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int kvm_create_guest_memfd(uint64_t size, uint64_t flags, Error **errp)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
struct kvm_create_guest_memfd guest_memfd = {
|
||||||
|
.size = size,
|
||||||
|
.flags = flags,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!kvm_guest_memfd_supported) {
|
||||||
|
error_setg(errp, "KVM doesn't support guest memfd\n");
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = kvm_vm_ioctl(kvm_state, KVM_CREATE_GUEST_MEMFD, &guest_memfd);
|
||||||
|
if (fd < 0) {
|
||||||
|
error_setg_errno(errp, errno, "%s: error creating kvm guest memfd\n", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ kvm_irqchip_update_msi_route(int virq) "Updating MSI route virq=%d"
|
|||||||
kvm_irqchip_release_virq(int virq) "virq %d"
|
kvm_irqchip_release_virq(int virq) "virq %d"
|
||||||
kvm_set_ioeventfd_mmio(int fd, uint64_t addr, uint32_t val, bool assign, uint32_t size, bool datamatch) "fd: %d @0x%" PRIx64 " val=0x%x assign: %d size: %d match: %d"
|
kvm_set_ioeventfd_mmio(int fd, uint64_t addr, uint32_t val, bool assign, uint32_t size, bool datamatch) "fd: %d @0x%" PRIx64 " val=0x%x assign: %d size: %d match: %d"
|
||||||
kvm_set_ioeventfd_pio(int fd, uint16_t addr, uint32_t val, bool assign, uint32_t size, bool datamatch) "fd: %d @0x%x val=0x%x assign: %d size: %d match: %d"
|
kvm_set_ioeventfd_pio(int fd, uint16_t addr, uint32_t val, bool assign, uint32_t size, bool datamatch) "fd: %d @0x%x val=0x%x assign: %d size: %d match: %d"
|
||||||
kvm_set_user_memory(uint32_t slot, uint32_t flags, uint64_t guest_phys_addr, uint64_t memory_size, uint64_t userspace_addr, int ret) "Slot#%d flags=0x%x gpa=0x%"PRIx64 " size=0x%"PRIx64 " ua=0x%"PRIx64 " ret=%d"
|
kvm_set_user_memory(uint16_t as, uint16_t slot, uint32_t flags, uint64_t guest_phys_addr, uint64_t memory_size, uint64_t userspace_addr, uint32_t fd, uint64_t fd_offset, int ret) "AddrSpace#%d Slot#%d flags=0x%x gpa=0x%"PRIx64 " size=0x%"PRIx64 " ua=0x%"PRIx64 " guest_memfd=%d" " guest_memfd_offset=0x%" PRIx64 " ret=%d"
|
||||||
kvm_clear_dirty_log(uint32_t slot, uint64_t start, uint32_t size) "slot#%"PRId32" start 0x%"PRIx64" size 0x%"PRIx32
|
kvm_clear_dirty_log(uint32_t slot, uint64_t start, uint32_t size) "slot#%"PRId32" start 0x%"PRIx64" size 0x%"PRIx32
|
||||||
kvm_resample_fd_notify(int gsi) "gsi %d"
|
kvm_resample_fd_notify(int gsi) "gsi %d"
|
||||||
kvm_dirty_ring_full(int id) "vcpu %d"
|
kvm_dirty_ring_full(int id) "vcpu %d"
|
||||||
@@ -25,4 +25,4 @@ kvm_dirty_ring_reaper(const char *s) "%s"
|
|||||||
kvm_dirty_ring_reap(uint64_t count, int64_t t) "reaped %"PRIu64" pages (took %"PRIi64" us)"
|
kvm_dirty_ring_reap(uint64_t count, int64_t t) "reaped %"PRIu64" pages (took %"PRIi64" us)"
|
||||||
kvm_dirty_ring_reaper_kick(const char *reason) "%s"
|
kvm_dirty_ring_reaper_kick(const char *reason) "%s"
|
||||||
kvm_dirty_ring_flush(int finished) "%d"
|
kvm_dirty_ring_flush(int finished) "%d"
|
||||||
|
kvm_convert_memory(uint64_t start, uint64_t size, const char *msg) "start 0x%" PRIx64 " size 0x%" PRIx64 " %s"
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ static bool tb_lookup_cmp(const void *p, const void *d)
|
|||||||
const TranslationBlock *tb = p;
|
const TranslationBlock *tb = p;
|
||||||
const struct tb_desc *desc = d;
|
const struct tb_desc *desc = d;
|
||||||
|
|
||||||
if (tb->pc == desc->pc &&
|
if ((tb_cflags(tb) & CF_PCREL || tb->pc == desc->pc) &&
|
||||||
tb_page_addr0(tb) == desc->page_addr0 &&
|
tb_page_addr0(tb) == desc->page_addr0 &&
|
||||||
tb->cs_base == desc->cs_base &&
|
tb->cs_base == desc->cs_base &&
|
||||||
tb->flags == desc->flags &&
|
tb->flags == desc->flags &&
|
||||||
@@ -233,7 +233,7 @@ static TranslationBlock *tb_htable_lookup(CPUState *cpu, vaddr pc,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
desc.page_addr0 = phys_pc;
|
desc.page_addr0 = phys_pc;
|
||||||
h = tb_hash_func(phys_pc, pc,
|
h = tb_hash_func(phys_pc, (cflags & CF_PCREL ? 0 : pc),
|
||||||
flags, cs_base, cflags);
|
flags, cs_base, cflags);
|
||||||
return qht_lookup_custom(&tb_ctx.htable, &desc, h, tb_lookup_cmp);
|
return qht_lookup_custom(&tb_ctx.htable, &desc, h, tb_lookup_cmp);
|
||||||
}
|
}
|
||||||
@@ -721,7 +721,7 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
|
|||||||
&& cpu->neg.icount_decr.u16.low + cpu->icount_extra == 0) {
|
&& cpu->neg.icount_decr.u16.low + cpu->icount_extra == 0) {
|
||||||
/* Execute just one insn to trigger exception pending in the log */
|
/* Execute just one insn to trigger exception pending in the log */
|
||||||
cpu->cflags_next_tb = (curr_cflags(cpu) & ~CF_USE_ICOUNT)
|
cpu->cflags_next_tb = (curr_cflags(cpu) & ~CF_USE_ICOUNT)
|
||||||
| CF_NOIRQ | 1;
|
| CF_LAST_IO | CF_NOIRQ | 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -1479,8 +1479,7 @@ int probe_access_full(CPUArchState *env, vaddr addr, int size,
|
|||||||
|
|
||||||
/* Handle clean RAM pages. */
|
/* Handle clean RAM pages. */
|
||||||
if (unlikely(flags & TLB_NOTDIRTY)) {
|
if (unlikely(flags & TLB_NOTDIRTY)) {
|
||||||
int dirtysize = size == 0 ? 1 : size;
|
notdirty_write(env_cpu(env), addr, 1, *pfull, retaddr);
|
||||||
notdirty_write(env_cpu(env), addr, dirtysize, *pfull, retaddr);
|
|
||||||
flags &= ~TLB_NOTDIRTY;
|
flags &= ~TLB_NOTDIRTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1503,8 +1502,7 @@ int probe_access_full_mmu(CPUArchState *env, vaddr addr, int size,
|
|||||||
|
|
||||||
/* Handle clean RAM pages. */
|
/* Handle clean RAM pages. */
|
||||||
if (unlikely(flags & TLB_NOTDIRTY)) {
|
if (unlikely(flags & TLB_NOTDIRTY)) {
|
||||||
int dirtysize = size == 0 ? 1 : size;
|
notdirty_write(env_cpu(env), addr, 1, *pfull, 0);
|
||||||
notdirty_write(env_cpu(env), addr, dirtysize, *pfull, 0);
|
|
||||||
flags &= ~TLB_NOTDIRTY;
|
flags &= ~TLB_NOTDIRTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1526,8 +1524,7 @@ int probe_access_flags(CPUArchState *env, vaddr addr, int size,
|
|||||||
|
|
||||||
/* Handle clean RAM pages. */
|
/* Handle clean RAM pages. */
|
||||||
if (unlikely(flags & TLB_NOTDIRTY)) {
|
if (unlikely(flags & TLB_NOTDIRTY)) {
|
||||||
int dirtysize = size == 0 ? 1 : size;
|
notdirty_write(env_cpu(env), addr, 1, full, retaddr);
|
||||||
notdirty_write(env_cpu(env), addr, dirtysize, full, retaddr);
|
|
||||||
flags &= ~TLB_NOTDIRTY;
|
flags &= ~TLB_NOTDIRTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1563,7 +1560,7 @@ void *probe_access(CPUArchState *env, vaddr addr, int size,
|
|||||||
|
|
||||||
/* Handle clean RAM pages. */
|
/* Handle clean RAM pages. */
|
||||||
if (flags & TLB_NOTDIRTY) {
|
if (flags & TLB_NOTDIRTY) {
|
||||||
notdirty_write(env_cpu(env), addr, size, full, retaddr);
|
notdirty_write(env_cpu(env), addr, 1, full, retaddr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ static bool tb_cmp(const void *ap, const void *bp)
|
|||||||
const TranslationBlock *a = ap;
|
const TranslationBlock *a = ap;
|
||||||
const TranslationBlock *b = bp;
|
const TranslationBlock *b = bp;
|
||||||
|
|
||||||
return (a->pc == b->pc &&
|
return ((tb_cflags(a) & CF_PCREL || a->pc == b->pc) &&
|
||||||
a->cs_base == b->cs_base &&
|
a->cs_base == b->cs_base &&
|
||||||
a->flags == b->flags &&
|
a->flags == b->flags &&
|
||||||
(tb_cflags(a) & ~CF_INVALID) == (tb_cflags(b) & ~CF_INVALID) &&
|
(tb_cflags(a) & ~CF_INVALID) == (tb_cflags(b) & ~CF_INVALID) &&
|
||||||
@@ -916,7 +916,7 @@ static void do_tb_phys_invalidate(TranslationBlock *tb, bool rm_from_page_list)
|
|||||||
|
|
||||||
/* remove the TB from the hash list */
|
/* remove the TB from the hash list */
|
||||||
phys_pc = tb_page_addr0(tb);
|
phys_pc = tb_page_addr0(tb);
|
||||||
h = tb_hash_func(phys_pc, tb->pc,
|
h = tb_hash_func(phys_pc, (orig_cflags & CF_PCREL ? 0 : tb->pc),
|
||||||
tb->flags, tb->cs_base, orig_cflags);
|
tb->flags, tb->cs_base, orig_cflags);
|
||||||
if (!qht_remove(&tb_ctx.htable, tb, h)) {
|
if (!qht_remove(&tb_ctx.htable, tb, h)) {
|
||||||
return;
|
return;
|
||||||
@@ -983,7 +983,7 @@ TranslationBlock *tb_link_page(TranslationBlock *tb)
|
|||||||
tb_record(tb);
|
tb_record(tb);
|
||||||
|
|
||||||
/* add in the hash table */
|
/* add in the hash table */
|
||||||
h = tb_hash_func(tb_page_addr0(tb), tb->pc,
|
h = tb_hash_func(tb_page_addr0(tb), (tb->cflags & CF_PCREL ? 0 : tb->pc),
|
||||||
tb->flags, tb->cs_base, tb->cflags);
|
tb->flags, tb->cs_base, tb->cflags);
|
||||||
qht_insert(&tb_ctx.htable, tb, h, &existing_tb);
|
qht_insert(&tb_ctx.htable, tb, h, &existing_tb);
|
||||||
|
|
||||||
@@ -1083,7 +1083,8 @@ bool tb_invalidate_phys_page_unwind(tb_page_addr_t addr, uintptr_t pc)
|
|||||||
if (current_tb_modified) {
|
if (current_tb_modified) {
|
||||||
/* Force execution of one insn next time. */
|
/* Force execution of one insn next time. */
|
||||||
CPUState *cpu = current_cpu;
|
CPUState *cpu = current_cpu;
|
||||||
cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(current_cpu);
|
cpu->cflags_next_tb =
|
||||||
|
1 | CF_LAST_IO | CF_NOIRQ | curr_cflags(current_cpu);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -1153,7 +1154,8 @@ tb_invalidate_phys_page_range__locked(struct page_collection *pages,
|
|||||||
if (current_tb_modified) {
|
if (current_tb_modified) {
|
||||||
page_collection_unlock(pages);
|
page_collection_unlock(pages);
|
||||||
/* Force execution of one insn next time. */
|
/* Force execution of one insn next time. */
|
||||||
current_cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(current_cpu);
|
current_cpu->cflags_next_tb =
|
||||||
|
1 | CF_LAST_IO | CF_NOIRQ | curr_cflags(current_cpu);
|
||||||
mmap_unlock();
|
mmap_unlock();
|
||||||
cpu_loop_exit_noexc(current_cpu);
|
cpu_loop_exit_noexc(current_cpu);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -304,7 +304,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
|||||||
|
|
||||||
if (phys_pc == -1) {
|
if (phys_pc == -1) {
|
||||||
/* Generate a one-shot TB with 1 insn in it */
|
/* Generate a one-shot TB with 1 insn in it */
|
||||||
cflags = (cflags & ~CF_COUNT_MASK) | 1;
|
cflags = (cflags & ~CF_COUNT_MASK) | CF_LAST_IO | 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
max_insns = cflags & CF_COUNT_MASK;
|
max_insns = cflags & CF_COUNT_MASK;
|
||||||
@@ -327,7 +327,9 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
|||||||
|
|
||||||
gen_code_buf = tcg_ctx->code_gen_ptr;
|
gen_code_buf = tcg_ctx->code_gen_ptr;
|
||||||
tb->tc.ptr = tcg_splitwx_to_rx(gen_code_buf);
|
tb->tc.ptr = tcg_splitwx_to_rx(gen_code_buf);
|
||||||
|
if (!(cflags & CF_PCREL)) {
|
||||||
tb->pc = pc;
|
tb->pc = pc;
|
||||||
|
}
|
||||||
tb->cs_base = cs_base;
|
tb->cs_base = cs_base;
|
||||||
tb->flags = flags;
|
tb->flags = flags;
|
||||||
tb->cflags = cflags;
|
tb->cflags = cflags;
|
||||||
@@ -630,7 +632,7 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
|
|||||||
* operations only (which execute after completion) so we don't
|
* operations only (which execute after completion) so we don't
|
||||||
* double instrument the instruction.
|
* double instrument the instruction.
|
||||||
*/
|
*/
|
||||||
cpu->cflags_next_tb = curr_cflags(cpu) | CF_MEMI_ONLY | n;
|
cpu->cflags_next_tb = curr_cflags(cpu) | CF_MEMI_ONLY | CF_LAST_IO | n;
|
||||||
|
|
||||||
if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
|
if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
|
||||||
vaddr pc = log_pc(cpu, tb);
|
vaddr pc = log_pc(cpu, tb);
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ static TCGOp *gen_tb_start(DisasContextBase *db, uint32_t cflags)
|
|||||||
* each translation block. The cost is minimal, plus it would be
|
* each translation block. The cost is minimal, plus it would be
|
||||||
* very easy to forget doing it in the translator.
|
* very easy to forget doing it in the translator.
|
||||||
*/
|
*/
|
||||||
set_can_do_io(db, db->max_insns == 1);
|
set_can_do_io(db, db->max_insns == 1 && (cflags & CF_LAST_IO));
|
||||||
|
|
||||||
return icount_start_insn;
|
return icount_start_insn;
|
||||||
}
|
}
|
||||||
@@ -151,7 +151,13 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
|||||||
ops->tb_start(db, cpu);
|
ops->tb_start(db, cpu);
|
||||||
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
|
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
|
||||||
|
|
||||||
plugin_enabled = plugin_gen_tb_start(cpu, db, cflags & CF_MEMI_ONLY);
|
if (cflags & CF_MEMI_ONLY) {
|
||||||
|
/* We should only see CF_MEMI_ONLY for io_recompile. */
|
||||||
|
assert(cflags & CF_LAST_IO);
|
||||||
|
plugin_enabled = plugin_gen_tb_start(cpu, db, true);
|
||||||
|
} else {
|
||||||
|
plugin_enabled = plugin_gen_tb_start(cpu, db, false);
|
||||||
|
}
|
||||||
db->plugin_enabled = plugin_enabled;
|
db->plugin_enabled = plugin_enabled;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
@@ -163,13 +169,11 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
|||||||
plugin_gen_insn_start(cpu, db);
|
plugin_gen_insn_start(cpu, db);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Disassemble one instruction. The translate_insn hook should
|
||||||
* Disassemble one instruction. The translate_insn hook should
|
update db->pc_next and db->is_jmp to indicate what should be
|
||||||
* update db->pc_next and db->is_jmp to indicate what should be
|
done next -- either exiting this loop or locate the start of
|
||||||
* done next -- either exiting this loop or locate the start of
|
the next instruction. */
|
||||||
* the next instruction.
|
if (db->num_insns == db->max_insns && (cflags & CF_LAST_IO)) {
|
||||||
*/
|
|
||||||
if (db->num_insns == db->max_insns) {
|
|
||||||
/* Accept I/O on the last instruction. */
|
/* Accept I/O on the last instruction. */
|
||||||
set_can_do_io(db, true);
|
set_can_do_io(db, true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1744,7 +1744,7 @@ static AudioState *audio_init(Audiodev *dev, Error **errp)
|
|||||||
if (driver) {
|
if (driver) {
|
||||||
done = !audio_driver_init(s, driver, dev, errp);
|
done = !audio_driver_init(s, driver, dev, errp);
|
||||||
} else {
|
} else {
|
||||||
error_setg(errp, "Unknown audio driver `%s'", drvname);
|
error_setg(errp, "Unknown audio driver `%s'\n", drvname);
|
||||||
}
|
}
|
||||||
if (!done) {
|
if (!done) {
|
||||||
goto out;
|
goto out;
|
||||||
@@ -1758,15 +1758,12 @@ static AudioState *audio_init(Audiodev *dev, Error **errp)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
s->dev = dev = e->dev;
|
s->dev = dev = e->dev;
|
||||||
QSIMPLEQ_REMOVE_HEAD(&default_audiodevs, next);
|
|
||||||
g_free(e);
|
|
||||||
drvname = AudiodevDriver_str(dev->driver);
|
drvname = AudiodevDriver_str(dev->driver);
|
||||||
driver = audio_driver_lookup(drvname);
|
driver = audio_driver_lookup(drvname);
|
||||||
if (!audio_driver_init(s, driver, dev, NULL)) {
|
if (!audio_driver_init(s, driver, dev, NULL)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
qapi_free_Audiodev(dev);
|
QSIMPLEQ_REMOVE_HEAD(&default_audiodevs, next);
|
||||||
s->dev = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -398,7 +398,6 @@ static void cryptodev_backend_set_ops(Object *obj, Visitor *v,
|
|||||||
static void
|
static void
|
||||||
cryptodev_backend_complete(UserCreatable *uc, Error **errp)
|
cryptodev_backend_complete(UserCreatable *uc, Error **errp)
|
||||||
{
|
{
|
||||||
ERRP_GUARD();
|
|
||||||
CryptoDevBackend *backend = CRYPTODEV_BACKEND(uc);
|
CryptoDevBackend *backend = CRYPTODEV_BACKEND(uc);
|
||||||
CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_GET_CLASS(uc);
|
CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_GET_CLASS(uc);
|
||||||
uint32_t services;
|
uint32_t services;
|
||||||
@@ -407,20 +406,11 @@ cryptodev_backend_complete(UserCreatable *uc, Error **errp)
|
|||||||
QTAILQ_INIT(&backend->opinfos);
|
QTAILQ_INIT(&backend->opinfos);
|
||||||
value = backend->tc.buckets[THROTTLE_OPS_TOTAL].avg;
|
value = backend->tc.buckets[THROTTLE_OPS_TOTAL].avg;
|
||||||
cryptodev_backend_set_throttle(backend, THROTTLE_OPS_TOTAL, value, errp);
|
cryptodev_backend_set_throttle(backend, THROTTLE_OPS_TOTAL, value, errp);
|
||||||
if (*errp) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
value = backend->tc.buckets[THROTTLE_BPS_TOTAL].avg;
|
value = backend->tc.buckets[THROTTLE_BPS_TOTAL].avg;
|
||||||
cryptodev_backend_set_throttle(backend, THROTTLE_BPS_TOTAL, value, errp);
|
cryptodev_backend_set_throttle(backend, THROTTLE_BPS_TOTAL, value, errp);
|
||||||
if (*errp) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bc->init) {
|
if (bc->init) {
|
||||||
bc->init(backend, errp);
|
bc->init(backend, errp);
|
||||||
if (*errp) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
services = backend->conf.crypto_services;
|
services = backend->conf.crypto_services;
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
|
|||||||
ram_flags |= fb->readonly ? RAM_READONLY_FD : 0;
|
ram_flags |= fb->readonly ? RAM_READONLY_FD : 0;
|
||||||
ram_flags |= fb->rom == ON_OFF_AUTO_ON ? RAM_READONLY : 0;
|
ram_flags |= fb->rom == ON_OFF_AUTO_ON ? RAM_READONLY : 0;
|
||||||
ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
|
ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
|
||||||
|
ram_flags |= backend->require_guest_memfd ? RAM_GUEST_MEMFD : 0;
|
||||||
ram_flags |= fb->is_pmem ? RAM_PMEM : 0;
|
ram_flags |= fb->is_pmem ? RAM_PMEM : 0;
|
||||||
ram_flags |= RAM_NAMED_FILE;
|
ram_flags |= RAM_NAMED_FILE;
|
||||||
memory_region_init_ram_from_file(&backend->mr, OBJECT(backend), name,
|
memory_region_init_ram_from_file(&backend->mr, OBJECT(backend), name,
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ memfd_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
|
|||||||
name = host_memory_backend_get_name(backend);
|
name = host_memory_backend_get_name(backend);
|
||||||
ram_flags = backend->share ? RAM_SHARED : 0;
|
ram_flags = backend->share ? RAM_SHARED : 0;
|
||||||
ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
|
ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
|
||||||
|
ram_flags |= backend->require_guest_memfd ? RAM_GUEST_MEMFD : 0;
|
||||||
memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend), name,
|
memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend), name,
|
||||||
backend->size, ram_flags, fd, 0, errp);
|
backend->size, ram_flags, fd, 0, errp);
|
||||||
g_free(name);
|
g_free(name);
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ ram_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
|
|||||||
name = host_memory_backend_get_name(backend);
|
name = host_memory_backend_get_name(backend);
|
||||||
ram_flags = backend->share ? RAM_SHARED : 0;
|
ram_flags = backend->share ? RAM_SHARED : 0;
|
||||||
ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
|
ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
|
||||||
|
ram_flags |= backend->require_guest_memfd ? RAM_GUEST_MEMFD : 0;
|
||||||
memory_region_init_ram_flags_nomigrate(&backend->mr, OBJECT(backend), name,
|
memory_region_init_ram_flags_nomigrate(&backend->mr, OBJECT(backend), name,
|
||||||
backend->size, ram_flags, errp);
|
backend->size, ram_flags, errp);
|
||||||
g_free(name);
|
g_free(name);
|
||||||
|
|||||||
@@ -279,6 +279,7 @@ static void host_memory_backend_init(Object *obj)
|
|||||||
/* TODO: convert access to globals to compat properties */
|
/* TODO: convert access to globals to compat properties */
|
||||||
backend->merge = machine_mem_merge(machine);
|
backend->merge = machine_mem_merge(machine);
|
||||||
backend->dump = machine_dump_guest_core(machine);
|
backend->dump = machine_dump_guest_core(machine);
|
||||||
|
backend->require_guest_memfd = machine_require_guest_memfd(machine);
|
||||||
backend->reserve = true;
|
backend->reserve = true;
|
||||||
backend->prealloc_threads = machine->smp.cpus;
|
backend->prealloc_threads = machine->smp.cpus;
|
||||||
}
|
}
|
||||||
|
|||||||
39
block.c
39
block.c
@@ -1713,7 +1713,7 @@ open_failed:
|
|||||||
bdrv_unref_child(bs, bs->file);
|
bdrv_unref_child(bs, bs->file);
|
||||||
assert(!bs->file);
|
assert(!bs->file);
|
||||||
}
|
}
|
||||||
bdrv_graph_wrunlock(NULL);
|
bdrv_graph_wrunlock();
|
||||||
|
|
||||||
g_free(bs->opaque);
|
g_free(bs->opaque);
|
||||||
bs->opaque = NULL;
|
bs->opaque = NULL;
|
||||||
@@ -3577,7 +3577,7 @@ int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
|
|||||||
bdrv_drained_begin(drain_bs);
|
bdrv_drained_begin(drain_bs);
|
||||||
bdrv_graph_wrlock(backing_hd);
|
bdrv_graph_wrlock(backing_hd);
|
||||||
ret = bdrv_set_backing_hd_drained(bs, backing_hd, errp);
|
ret = bdrv_set_backing_hd_drained(bs, backing_hd, errp);
|
||||||
bdrv_graph_wrunlock(backing_hd);
|
bdrv_graph_wrunlock();
|
||||||
bdrv_drained_end(drain_bs);
|
bdrv_drained_end(drain_bs);
|
||||||
bdrv_unref(drain_bs);
|
bdrv_unref(drain_bs);
|
||||||
|
|
||||||
@@ -3796,7 +3796,7 @@ BdrvChild *bdrv_open_child(const char *filename,
|
|||||||
child = bdrv_attach_child(parent, bs, bdref_key, child_class, child_role,
|
child = bdrv_attach_child(parent, bs, bdref_key, child_class, child_role,
|
||||||
errp);
|
errp);
|
||||||
aio_context_release(ctx);
|
aio_context_release(ctx);
|
||||||
bdrv_graph_wrunlock(NULL);
|
bdrv_graph_wrunlock();
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
@@ -4652,7 +4652,7 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
|
|||||||
|
|
||||||
bdrv_graph_wrlock(NULL);
|
bdrv_graph_wrlock(NULL);
|
||||||
tran_commit(tran);
|
tran_commit(tran);
|
||||||
bdrv_graph_wrunlock(NULL);
|
bdrv_graph_wrunlock();
|
||||||
|
|
||||||
QTAILQ_FOREACH_REVERSE(bs_entry, bs_queue, entry) {
|
QTAILQ_FOREACH_REVERSE(bs_entry, bs_queue, entry) {
|
||||||
BlockDriverState *bs = bs_entry->state.bs;
|
BlockDriverState *bs = bs_entry->state.bs;
|
||||||
@@ -4671,7 +4671,7 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
|
|||||||
abort:
|
abort:
|
||||||
bdrv_graph_wrlock(NULL);
|
bdrv_graph_wrlock(NULL);
|
||||||
tran_abort(tran);
|
tran_abort(tran);
|
||||||
bdrv_graph_wrunlock(NULL);
|
bdrv_graph_wrunlock();
|
||||||
|
|
||||||
QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
|
QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
|
||||||
if (bs_entry->prepared) {
|
if (bs_entry->prepared) {
|
||||||
@@ -4857,7 +4857,7 @@ bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
|
|||||||
ret = bdrv_set_file_or_backing_noperm(bs, new_child_bs, is_backing,
|
ret = bdrv_set_file_or_backing_noperm(bs, new_child_bs, is_backing,
|
||||||
tran, errp);
|
tran, errp);
|
||||||
|
|
||||||
bdrv_graph_wrunlock_ctx(ctx);
|
bdrv_graph_wrunlock();
|
||||||
|
|
||||||
if (old_ctx != ctx) {
|
if (old_ctx != ctx) {
|
||||||
aio_context_release(ctx);
|
aio_context_release(ctx);
|
||||||
@@ -5216,7 +5216,7 @@ static void bdrv_close(BlockDriverState *bs)
|
|||||||
|
|
||||||
assert(!bs->backing);
|
assert(!bs->backing);
|
||||||
assert(!bs->file);
|
assert(!bs->file);
|
||||||
bdrv_graph_wrunlock(bs);
|
bdrv_graph_wrunlock();
|
||||||
|
|
||||||
g_free(bs->opaque);
|
g_free(bs->opaque);
|
||||||
bs->opaque = NULL;
|
bs->opaque = NULL;
|
||||||
@@ -5511,7 +5511,7 @@ int bdrv_drop_filter(BlockDriverState *bs, Error **errp)
|
|||||||
bdrv_drained_begin(child_bs);
|
bdrv_drained_begin(child_bs);
|
||||||
bdrv_graph_wrlock(bs);
|
bdrv_graph_wrlock(bs);
|
||||||
ret = bdrv_replace_node_common(bs, child_bs, true, true, errp);
|
ret = bdrv_replace_node_common(bs, child_bs, true, true, errp);
|
||||||
bdrv_graph_wrunlock(bs);
|
bdrv_graph_wrunlock();
|
||||||
bdrv_drained_end(child_bs);
|
bdrv_drained_end(child_bs);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -5593,7 +5593,7 @@ out:
|
|||||||
tran_finalize(tran, ret);
|
tran_finalize(tran, ret);
|
||||||
|
|
||||||
bdrv_refresh_limits(bs_top, NULL, NULL);
|
bdrv_refresh_limits(bs_top, NULL, NULL);
|
||||||
bdrv_graph_wrunlock(bs_top);
|
bdrv_graph_wrunlock();
|
||||||
|
|
||||||
bdrv_drained_end(bs_top);
|
bdrv_drained_end(bs_top);
|
||||||
bdrv_drained_end(bs_new);
|
bdrv_drained_end(bs_new);
|
||||||
@@ -5631,7 +5631,7 @@ int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs,
|
|||||||
|
|
||||||
tran_finalize(tran, ret);
|
tran_finalize(tran, ret);
|
||||||
|
|
||||||
bdrv_graph_wrunlock(new_bs);
|
bdrv_graph_wrunlock();
|
||||||
bdrv_drained_end(old_bs);
|
bdrv_drained_end(old_bs);
|
||||||
bdrv_drained_end(new_bs);
|
bdrv_drained_end(new_bs);
|
||||||
bdrv_unref(old_bs);
|
bdrv_unref(old_bs);
|
||||||
@@ -5720,7 +5720,7 @@ BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *options,
|
|||||||
bdrv_drained_begin(new_node_bs);
|
bdrv_drained_begin(new_node_bs);
|
||||||
bdrv_graph_wrlock(new_node_bs);
|
bdrv_graph_wrlock(new_node_bs);
|
||||||
ret = bdrv_replace_node(bs, new_node_bs, errp);
|
ret = bdrv_replace_node(bs, new_node_bs, errp);
|
||||||
bdrv_graph_wrunlock(new_node_bs);
|
bdrv_graph_wrunlock();
|
||||||
bdrv_drained_end(new_node_bs);
|
bdrv_drained_end(new_node_bs);
|
||||||
bdrv_drained_end(bs);
|
bdrv_drained_end(bs);
|
||||||
bdrv_unref(bs);
|
bdrv_unref(bs);
|
||||||
@@ -6015,7 +6015,7 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
|
|||||||
* That's a FIXME.
|
* That's a FIXME.
|
||||||
*/
|
*/
|
||||||
bdrv_replace_node_common(top, base, false, false, &local_err);
|
bdrv_replace_node_common(top, base, false, false, &local_err);
|
||||||
bdrv_graph_wrunlock(base);
|
bdrv_graph_wrunlock();
|
||||||
|
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_report_err(local_err);
|
error_report_err(local_err);
|
||||||
@@ -6052,7 +6052,7 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
|
|||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
exit_wrlock:
|
exit_wrlock:
|
||||||
bdrv_graph_wrunlock(base);
|
bdrv_graph_wrunlock();
|
||||||
exit:
|
exit:
|
||||||
bdrv_drained_end(base);
|
bdrv_drained_end(base);
|
||||||
bdrv_unref(top);
|
bdrv_unref(top);
|
||||||
@@ -7254,16 +7254,6 @@ void bdrv_unref(BlockDriverState *bs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bdrv_schedule_unref_bh(void *opaque)
|
|
||||||
{
|
|
||||||
BlockDriverState *bs = opaque;
|
|
||||||
AioContext *ctx = bdrv_get_aio_context(bs);
|
|
||||||
|
|
||||||
aio_context_acquire(ctx);
|
|
||||||
bdrv_unref(bs);
|
|
||||||
aio_context_release(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Release a BlockDriverState reference while holding the graph write lock.
|
* Release a BlockDriverState reference while holding the graph write lock.
|
||||||
*
|
*
|
||||||
@@ -7277,7 +7267,8 @@ void bdrv_schedule_unref(BlockDriverState *bs)
|
|||||||
if (!bs) {
|
if (!bs) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
aio_bh_schedule_oneshot(qemu_get_aio_context(), bdrv_schedule_unref_bh, bs);
|
aio_bh_schedule_oneshot(qemu_get_aio_context(),
|
||||||
|
(QEMUBHFunc *) bdrv_unref, bs);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BdrvOpBlocker {
|
struct BdrvOpBlocker {
|
||||||
|
|||||||
@@ -499,7 +499,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
|||||||
bdrv_graph_wrlock(target);
|
bdrv_graph_wrlock(target);
|
||||||
block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
|
block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
|
||||||
&error_abort);
|
&error_abort);
|
||||||
bdrv_graph_wrunlock(target);
|
bdrv_graph_wrunlock();
|
||||||
|
|
||||||
return &job->common;
|
return &job->common;
|
||||||
|
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ fail_log:
|
|||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
bdrv_graph_wrlock(NULL);
|
bdrv_graph_wrlock(NULL);
|
||||||
bdrv_unref_child(bs, s->log_file);
|
bdrv_unref_child(bs, s->log_file);
|
||||||
bdrv_graph_wrunlock(NULL);
|
bdrv_graph_wrunlock();
|
||||||
s->log_file = NULL;
|
s->log_file = NULL;
|
||||||
}
|
}
|
||||||
fail:
|
fail:
|
||||||
@@ -268,7 +268,7 @@ static void blk_log_writes_close(BlockDriverState *bs)
|
|||||||
bdrv_graph_wrlock(NULL);
|
bdrv_graph_wrlock(NULL);
|
||||||
bdrv_unref_child(bs, s->log_file);
|
bdrv_unref_child(bs, s->log_file);
|
||||||
s->log_file = NULL;
|
s->log_file = NULL;
|
||||||
bdrv_graph_wrunlock(NULL);
|
bdrv_graph_wrunlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t coroutine_fn GRAPH_RDLOCK
|
static int64_t coroutine_fn GRAPH_RDLOCK
|
||||||
@@ -328,39 +328,22 @@ static void coroutine_fn GRAPH_RDLOCK
|
|||||||
blk_log_writes_co_do_log(BlkLogWritesLogReq *lr)
|
blk_log_writes_co_do_log(BlkLogWritesLogReq *lr)
|
||||||
{
|
{
|
||||||
BDRVBlkLogWritesState *s = lr->bs->opaque;
|
BDRVBlkLogWritesState *s = lr->bs->opaque;
|
||||||
|
uint64_t cur_log_offset = s->cur_log_sector << s->sectorbits;
|
||||||
/*
|
|
||||||
* Determine the offsets and sizes of different parts of the entry, and
|
|
||||||
* update the state of the driver.
|
|
||||||
*
|
|
||||||
* This needs to be done in one go, before any actual I/O is done, as the
|
|
||||||
* log entry may have to be written in two parts, and the state of the
|
|
||||||
* driver may be modified by other driver operations while waiting for the
|
|
||||||
* I/O to complete.
|
|
||||||
*/
|
|
||||||
const uint64_t entry_start_sector = s->cur_log_sector;
|
|
||||||
const uint64_t entry_offset = entry_start_sector << s->sectorbits;
|
|
||||||
const uint64_t qiov_aligned_size = ROUND_UP(lr->qiov->size, s->sectorsize);
|
|
||||||
const uint64_t entry_aligned_size = qiov_aligned_size +
|
|
||||||
ROUND_UP(lr->zero_size, s->sectorsize);
|
|
||||||
const uint64_t entry_nr_sectors = entry_aligned_size >> s->sectorbits;
|
|
||||||
|
|
||||||
s->nr_entries++;
|
s->nr_entries++;
|
||||||
s->cur_log_sector += entry_nr_sectors;
|
s->cur_log_sector +=
|
||||||
|
ROUND_UP(lr->qiov->size, s->sectorsize) >> s->sectorbits;
|
||||||
|
|
||||||
/*
|
lr->log_ret = bdrv_co_pwritev(s->log_file, cur_log_offset, lr->qiov->size,
|
||||||
* Write the log entry. Note that if this is a "write zeroes" operation,
|
|
||||||
* only the entry header is written here, with the zeroing being done
|
|
||||||
* separately below.
|
|
||||||
*/
|
|
||||||
lr->log_ret = bdrv_co_pwritev(s->log_file, entry_offset, lr->qiov->size,
|
|
||||||
lr->qiov, 0);
|
lr->qiov, 0);
|
||||||
|
|
||||||
/* Logging for the "write zeroes" operation */
|
/* Logging for the "write zeroes" operation */
|
||||||
if (lr->log_ret == 0 && lr->zero_size) {
|
if (lr->log_ret == 0 && lr->zero_size) {
|
||||||
const uint64_t zeroes_offset = entry_offset + qiov_aligned_size;
|
cur_log_offset = s->cur_log_sector << s->sectorbits;
|
||||||
|
s->cur_log_sector +=
|
||||||
|
ROUND_UP(lr->zero_size, s->sectorsize) >> s->sectorbits;
|
||||||
|
|
||||||
lr->log_ret = bdrv_co_pwrite_zeroes(s->log_file, zeroes_offset,
|
lr->log_ret = bdrv_co_pwrite_zeroes(s->log_file, cur_log_offset,
|
||||||
lr->zero_size, 0);
|
lr->zero_size, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ static void blkverify_close(BlockDriverState *bs)
|
|||||||
bdrv_graph_wrlock(NULL);
|
bdrv_graph_wrlock(NULL);
|
||||||
bdrv_unref_child(bs, s->test_file);
|
bdrv_unref_child(bs, s->test_file);
|
||||||
s->test_file = NULL;
|
s->test_file = NULL;
|
||||||
bdrv_graph_wrunlock(NULL);
|
bdrv_graph_wrunlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t coroutine_fn GRAPH_RDLOCK
|
static int64_t coroutine_fn GRAPH_RDLOCK
|
||||||
|
|||||||
@@ -882,14 +882,11 @@ BlockBackend *blk_by_public(BlockBackendPublic *public)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Disassociates the currently associated BlockDriverState from @blk.
|
* Disassociates the currently associated BlockDriverState from @blk.
|
||||||
*
|
|
||||||
* The caller must hold the AioContext lock for the BlockBackend.
|
|
||||||
*/
|
*/
|
||||||
void blk_remove_bs(BlockBackend *blk)
|
void blk_remove_bs(BlockBackend *blk)
|
||||||
{
|
{
|
||||||
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
|
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
|
||||||
BdrvChild *root;
|
BdrvChild *root;
|
||||||
AioContext *ctx;
|
|
||||||
|
|
||||||
GLOBAL_STATE_CODE();
|
GLOBAL_STATE_CODE();
|
||||||
|
|
||||||
@@ -919,10 +916,9 @@ void blk_remove_bs(BlockBackend *blk)
|
|||||||
root = blk->root;
|
root = blk->root;
|
||||||
blk->root = NULL;
|
blk->root = NULL;
|
||||||
|
|
||||||
ctx = bdrv_get_aio_context(root->bs);
|
bdrv_graph_wrlock(NULL);
|
||||||
bdrv_graph_wrlock(root->bs);
|
|
||||||
bdrv_root_unref_child(root);
|
bdrv_root_unref_child(root);
|
||||||
bdrv_graph_wrunlock_ctx(ctx);
|
bdrv_graph_wrunlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -933,8 +929,6 @@ void blk_remove_bs(BlockBackend *blk)
|
|||||||
int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
|
int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
|
||||||
{
|
{
|
||||||
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
|
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
|
||||||
AioContext *ctx = bdrv_get_aio_context(bs);
|
|
||||||
|
|
||||||
GLOBAL_STATE_CODE();
|
GLOBAL_STATE_CODE();
|
||||||
bdrv_ref(bs);
|
bdrv_ref(bs);
|
||||||
bdrv_graph_wrlock(bs);
|
bdrv_graph_wrlock(bs);
|
||||||
@@ -942,7 +936,7 @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
|
|||||||
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
|
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
|
||||||
blk->perm, blk->shared_perm,
|
blk->perm, blk->shared_perm,
|
||||||
blk, errp);
|
blk, errp);
|
||||||
bdrv_graph_wrunlock_ctx(ctx);
|
bdrv_graph_wrunlock();
|
||||||
if (blk->root == NULL) {
|
if (blk->root == NULL) {
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ static void commit_abort(Job *job)
|
|||||||
bdrv_drained_begin(commit_top_backing_bs);
|
bdrv_drained_begin(commit_top_backing_bs);
|
||||||
bdrv_graph_wrlock(commit_top_backing_bs);
|
bdrv_graph_wrlock(commit_top_backing_bs);
|
||||||
bdrv_replace_node(s->commit_top_bs, commit_top_backing_bs, &error_abort);
|
bdrv_replace_node(s->commit_top_bs, commit_top_backing_bs, &error_abort);
|
||||||
bdrv_graph_wrunlock(commit_top_backing_bs);
|
bdrv_graph_wrunlock();
|
||||||
bdrv_drained_end(commit_top_backing_bs);
|
bdrv_drained_end(commit_top_backing_bs);
|
||||||
|
|
||||||
bdrv_unref(s->commit_top_bs);
|
bdrv_unref(s->commit_top_bs);
|
||||||
@@ -370,19 +370,19 @@ void commit_start(const char *job_id, BlockDriverState *bs,
|
|||||||
ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
|
ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
|
||||||
iter_shared_perms, errp);
|
iter_shared_perms, errp);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
bdrv_graph_wrunlock(top);
|
bdrv_graph_wrunlock();
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bdrv_freeze_backing_chain(commit_top_bs, base, errp) < 0) {
|
if (bdrv_freeze_backing_chain(commit_top_bs, base, errp) < 0) {
|
||||||
bdrv_graph_wrunlock(top);
|
bdrv_graph_wrunlock();
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
s->chain_frozen = true;
|
s->chain_frozen = true;
|
||||||
|
|
||||||
ret = block_job_add_bdrv(&s->common, "base", base, 0, BLK_PERM_ALL, errp);
|
ret = block_job_add_bdrv(&s->common, "base", base, 0, BLK_PERM_ALL, errp);
|
||||||
bdrv_graph_wrunlock(top);
|
bdrv_graph_wrunlock();
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -436,7 +436,7 @@ fail:
|
|||||||
bdrv_drained_begin(top);
|
bdrv_drained_begin(top);
|
||||||
bdrv_graph_wrlock(top);
|
bdrv_graph_wrlock(top);
|
||||||
bdrv_replace_node(commit_top_bs, top, &error_abort);
|
bdrv_replace_node(commit_top_bs, top, &error_abort);
|
||||||
bdrv_graph_wrunlock(top);
|
bdrv_graph_wrunlock();
|
||||||
bdrv_drained_end(top);
|
bdrv_drained_end(top);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -283,7 +283,6 @@ static void vu_blk_drained_begin(void *opaque)
|
|||||||
{
|
{
|
||||||
VuBlkExport *vexp = opaque;
|
VuBlkExport *vexp = opaque;
|
||||||
|
|
||||||
vexp->vu_server.quiescing = true;
|
|
||||||
vhost_user_server_detach_aio_context(&vexp->vu_server);
|
vhost_user_server_detach_aio_context(&vexp->vu_server);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,23 +291,19 @@ static void vu_blk_drained_end(void *opaque)
|
|||||||
{
|
{
|
||||||
VuBlkExport *vexp = opaque;
|
VuBlkExport *vexp = opaque;
|
||||||
|
|
||||||
vexp->vu_server.quiescing = false;
|
|
||||||
vhost_user_server_attach_aio_context(&vexp->vu_server, vexp->export.ctx);
|
vhost_user_server_attach_aio_context(&vexp->vu_server, vexp->export.ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ensures that bdrv_drained_begin() waits until in-flight requests complete
|
* Ensures that bdrv_drained_begin() waits until in-flight requests complete.
|
||||||
* and the server->co_trip coroutine has terminated. It will be restarted in
|
|
||||||
* vhost_user_server_attach_aio_context().
|
|
||||||
*
|
*
|
||||||
* Called with vexp->export.ctx acquired.
|
* Called with vexp->export.ctx acquired.
|
||||||
*/
|
*/
|
||||||
static bool vu_blk_drained_poll(void *opaque)
|
static bool vu_blk_drained_poll(void *opaque)
|
||||||
{
|
{
|
||||||
VuBlkExport *vexp = opaque;
|
VuBlkExport *vexp = opaque;
|
||||||
VuServer *server = &vexp->vu_server;
|
|
||||||
|
|
||||||
return server->co_trip || vhost_user_server_has_in_flight(server);
|
return vhost_user_server_has_in_flight(&vexp->vu_server);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const BlockDevOps vu_blk_dev_ops = {
|
static const BlockDevOps vu_blk_dev_ops = {
|
||||||
|
|||||||
@@ -161,21 +161,11 @@ void no_coroutine_fn bdrv_graph_wrlock(BlockDriverState *bs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void no_coroutine_fn bdrv_graph_wrunlock_ctx(AioContext *ctx)
|
void bdrv_graph_wrunlock(void)
|
||||||
{
|
{
|
||||||
GLOBAL_STATE_CODE();
|
GLOBAL_STATE_CODE();
|
||||||
assert(qatomic_read(&has_writer));
|
assert(qatomic_read(&has_writer));
|
||||||
|
|
||||||
/*
|
|
||||||
* Release only non-mainloop AioContext. The mainloop often relies on the
|
|
||||||
* BQL and doesn't lock the main AioContext before doing things.
|
|
||||||
*/
|
|
||||||
if (ctx && ctx != qemu_get_aio_context()) {
|
|
||||||
aio_context_release(ctx);
|
|
||||||
} else {
|
|
||||||
ctx = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
WITH_QEMU_LOCK_GUARD(&aio_context_list_lock) {
|
WITH_QEMU_LOCK_GUARD(&aio_context_list_lock) {
|
||||||
/*
|
/*
|
||||||
* No need for memory barriers, this works in pair with
|
* No need for memory barriers, this works in pair with
|
||||||
@@ -197,17 +187,6 @@ void no_coroutine_fn bdrv_graph_wrunlock_ctx(AioContext *ctx)
|
|||||||
* progress.
|
* progress.
|
||||||
*/
|
*/
|
||||||
aio_bh_poll(qemu_get_aio_context());
|
aio_bh_poll(qemu_get_aio_context());
|
||||||
|
|
||||||
if (ctx) {
|
|
||||||
aio_context_acquire(ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void no_coroutine_fn bdrv_graph_wrunlock(BlockDriverState *bs)
|
|
||||||
{
|
|
||||||
AioContext *ctx = bs ? bdrv_get_aio_context(bs) : NULL;
|
|
||||||
|
|
||||||
bdrv_graph_wrunlock_ctx(ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void coroutine_fn bdrv_graph_co_rdlock(void)
|
void coroutine_fn bdrv_graph_co_rdlock(void)
|
||||||
|
|||||||
10
block/io.c
10
block/io.c
@@ -2619,16 +2619,6 @@ bdrv_co_do_block_status(BlockDriverState *bs, bool want_zero,
|
|||||||
ret |= (ret2 & BDRV_BLOCK_ZERO);
|
ret |= (ret2 & BDRV_BLOCK_ZERO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Now that the recursive search was done, clear the flag. Otherwise,
|
|
||||||
* with more complicated block graphs like snapshot-access ->
|
|
||||||
* copy-before-write -> qcow2, where the return value will be propagated
|
|
||||||
* further up to a parent bdrv_co_do_block_status() call, both the
|
|
||||||
* BDRV_BLOCK_RECURSE and BDRV_BLOCK_ZERO flags would be set, which is
|
|
||||||
* not allowed.
|
|
||||||
*/
|
|
||||||
ret &= ~BDRV_BLOCK_RECURSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|||||||
@@ -773,7 +773,7 @@ static int mirror_exit_common(Job *job)
|
|||||||
"would not lead to an abrupt change of visible data",
|
"would not lead to an abrupt change of visible data",
|
||||||
to_replace->node_name, target_bs->node_name);
|
to_replace->node_name, target_bs->node_name);
|
||||||
}
|
}
|
||||||
bdrv_graph_wrunlock(target_bs);
|
bdrv_graph_wrunlock();
|
||||||
bdrv_drained_end(to_replace);
|
bdrv_drained_end(to_replace);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_report_err(local_err);
|
error_report_err(local_err);
|
||||||
@@ -798,7 +798,7 @@ static int mirror_exit_common(Job *job)
|
|||||||
block_job_remove_all_bdrv(bjob);
|
block_job_remove_all_bdrv(bjob);
|
||||||
bdrv_graph_wrlock(mirror_top_bs);
|
bdrv_graph_wrlock(mirror_top_bs);
|
||||||
bdrv_replace_node(mirror_top_bs, mirror_top_bs->backing->bs, &error_abort);
|
bdrv_replace_node(mirror_top_bs, mirror_top_bs->backing->bs, &error_abort);
|
||||||
bdrv_graph_wrunlock(mirror_top_bs);
|
bdrv_graph_wrunlock();
|
||||||
|
|
||||||
bdrv_drained_end(target_bs);
|
bdrv_drained_end(target_bs);
|
||||||
bdrv_unref(target_bs);
|
bdrv_unref(target_bs);
|
||||||
@@ -1920,7 +1920,7 @@ static BlockJob *mirror_start_job(
|
|||||||
BLK_PERM_CONSISTENT_READ,
|
BLK_PERM_CONSISTENT_READ,
|
||||||
errp);
|
errp);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
bdrv_graph_wrunlock(bs);
|
bdrv_graph_wrunlock();
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1965,17 +1965,17 @@ static BlockJob *mirror_start_job(
|
|||||||
ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
|
ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
|
||||||
iter_shared_perms, errp);
|
iter_shared_perms, errp);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
bdrv_graph_wrunlock(bs);
|
bdrv_graph_wrunlock();
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bdrv_freeze_backing_chain(mirror_top_bs, target, errp) < 0) {
|
if (bdrv_freeze_backing_chain(mirror_top_bs, target, errp) < 0) {
|
||||||
bdrv_graph_wrunlock(bs);
|
bdrv_graph_wrunlock();
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bdrv_graph_wrunlock(bs);
|
bdrv_graph_wrunlock();
|
||||||
|
|
||||||
QTAILQ_INIT(&s->ops_in_flight);
|
QTAILQ_INIT(&s->ops_in_flight);
|
||||||
|
|
||||||
@@ -2006,7 +2006,7 @@ fail:
|
|||||||
bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing,
|
bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing,
|
||||||
&error_abort);
|
&error_abort);
|
||||||
bdrv_replace_node(mirror_top_bs, bs, &error_abort);
|
bdrv_replace_node(mirror_top_bs, bs, &error_abort);
|
||||||
bdrv_graph_wrunlock(bs);
|
bdrv_graph_wrunlock();
|
||||||
bdrv_drained_end(bs);
|
bdrv_drained_end(bs);
|
||||||
|
|
||||||
bdrv_unref(mirror_top_bs);
|
bdrv_unref(mirror_top_bs);
|
||||||
|
|||||||
@@ -2809,7 +2809,7 @@ qcow2_do_close(BlockDriverState *bs, bool close_data_file)
|
|||||||
bdrv_graph_rdunlock_main_loop();
|
bdrv_graph_rdunlock_main_loop();
|
||||||
bdrv_graph_wrlock(NULL);
|
bdrv_graph_wrlock(NULL);
|
||||||
bdrv_unref_child(bs, s->data_file);
|
bdrv_unref_child(bs, s->data_file);
|
||||||
bdrv_graph_wrunlock(NULL);
|
bdrv_graph_wrunlock();
|
||||||
s->data_file = NULL;
|
s->data_file = NULL;
|
||||||
bdrv_graph_rdlock_main_loop();
|
bdrv_graph_rdlock_main_loop();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1044,7 +1044,7 @@ close_exit:
|
|||||||
}
|
}
|
||||||
bdrv_unref_child(bs, s->children[i]);
|
bdrv_unref_child(bs, s->children[i]);
|
||||||
}
|
}
|
||||||
bdrv_graph_wrunlock(NULL);
|
bdrv_graph_wrunlock();
|
||||||
g_free(s->children);
|
g_free(s->children);
|
||||||
g_free(opened);
|
g_free(opened);
|
||||||
exit:
|
exit:
|
||||||
@@ -1061,7 +1061,7 @@ static void quorum_close(BlockDriverState *bs)
|
|||||||
for (i = 0; i < s->num_children; i++) {
|
for (i = 0; i < s->num_children; i++) {
|
||||||
bdrv_unref_child(bs, s->children[i]);
|
bdrv_unref_child(bs, s->children[i]);
|
||||||
}
|
}
|
||||||
bdrv_graph_wrunlock(NULL);
|
bdrv_graph_wrunlock();
|
||||||
|
|
||||||
g_free(s->children);
|
g_free(s->children);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -568,7 +568,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
|
|||||||
&local_err);
|
&local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
bdrv_graph_wrunlock(bs);
|
bdrv_graph_wrunlock();
|
||||||
aio_context_release(aio_context);
|
aio_context_release(aio_context);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -579,7 +579,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
|
|||||||
BDRV_CHILD_DATA, &local_err);
|
BDRV_CHILD_DATA, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
bdrv_graph_wrunlock(bs);
|
bdrv_graph_wrunlock();
|
||||||
aio_context_release(aio_context);
|
aio_context_release(aio_context);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -592,7 +592,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
|
|||||||
if (!top_bs || !bdrv_is_root_node(top_bs) ||
|
if (!top_bs || !bdrv_is_root_node(top_bs) ||
|
||||||
!check_top_bs(top_bs, bs)) {
|
!check_top_bs(top_bs, bs)) {
|
||||||
error_setg(errp, "No top_bs or it is invalid");
|
error_setg(errp, "No top_bs or it is invalid");
|
||||||
bdrv_graph_wrunlock(bs);
|
bdrv_graph_wrunlock();
|
||||||
reopen_backing_file(bs, false, NULL);
|
reopen_backing_file(bs, false, NULL);
|
||||||
aio_context_release(aio_context);
|
aio_context_release(aio_context);
|
||||||
return;
|
return;
|
||||||
@@ -600,7 +600,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
|
|||||||
bdrv_op_block_all(top_bs, s->blocker);
|
bdrv_op_block_all(top_bs, s->blocker);
|
||||||
bdrv_op_unblock(top_bs, BLOCK_OP_TYPE_DATAPLANE, s->blocker);
|
bdrv_op_unblock(top_bs, BLOCK_OP_TYPE_DATAPLANE, s->blocker);
|
||||||
|
|
||||||
bdrv_graph_wrunlock(bs);
|
bdrv_graph_wrunlock();
|
||||||
|
|
||||||
s->backup_job = backup_job_create(
|
s->backup_job = backup_job_create(
|
||||||
NULL, s->secondary_disk->bs, s->hidden_disk->bs,
|
NULL, s->secondary_disk->bs, s->hidden_disk->bs,
|
||||||
@@ -696,7 +696,7 @@ static void replication_done(void *opaque, int ret)
|
|||||||
s->secondary_disk = NULL;
|
s->secondary_disk = NULL;
|
||||||
bdrv_unref_child(bs, s->hidden_disk);
|
bdrv_unref_child(bs, s->hidden_disk);
|
||||||
s->hidden_disk = NULL;
|
s->hidden_disk = NULL;
|
||||||
bdrv_graph_wrunlock(NULL);
|
bdrv_graph_wrunlock();
|
||||||
|
|
||||||
s->error = 0;
|
s->error = 0;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -196,10 +196,8 @@ bdrv_snapshot_fallback(BlockDriverState *bs)
|
|||||||
int bdrv_can_snapshot(BlockDriverState *bs)
|
int bdrv_can_snapshot(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BlockDriver *drv = bs->drv;
|
BlockDriver *drv = bs->drv;
|
||||||
|
|
||||||
GLOBAL_STATE_CODE();
|
GLOBAL_STATE_CODE();
|
||||||
|
if (!drv || !bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
|
||||||
if (!drv || !bdrv_is_inserted(bs) || !bdrv_is_writable(bs)) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,7 +292,7 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
|
|||||||
/* .bdrv_open() will re-attach it */
|
/* .bdrv_open() will re-attach it */
|
||||||
bdrv_graph_wrlock(NULL);
|
bdrv_graph_wrlock(NULL);
|
||||||
bdrv_unref_child(bs, fallback);
|
bdrv_unref_child(bs, fallback);
|
||||||
bdrv_graph_wrunlock(NULL);
|
bdrv_graph_wrunlock();
|
||||||
|
|
||||||
ret = bdrv_snapshot_goto(fallback_bs, snapshot_id, errp);
|
ret = bdrv_snapshot_goto(fallback_bs, snapshot_id, errp);
|
||||||
open_ret = drv->bdrv_open(bs, options, bs->open_flags, &local_err);
|
open_ret = drv->bdrv_open(bs, options, bs->open_flags, &local_err);
|
||||||
|
|||||||
@@ -99,9 +99,9 @@ static int stream_prepare(Job *job)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bdrv_graph_wrlock(s->target_bs);
|
bdrv_graph_wrlock(base);
|
||||||
bdrv_set_backing_hd_drained(unfiltered_bs, base, &local_err);
|
bdrv_set_backing_hd_drained(unfiltered_bs, base, &local_err);
|
||||||
bdrv_graph_wrunlock(s->target_bs);
|
bdrv_graph_wrunlock();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This call will do I/O, so the graph can change again from here on.
|
* This call will do I/O, so the graph can change again from here on.
|
||||||
@@ -369,7 +369,7 @@ void stream_start(const char *job_id, BlockDriverState *bs,
|
|||||||
bdrv_graph_wrlock(bs);
|
bdrv_graph_wrlock(bs);
|
||||||
if (block_job_add_bdrv(&s->common, "active node", bs, 0,
|
if (block_job_add_bdrv(&s->common, "active node", bs, 0,
|
||||||
basic_flags | BLK_PERM_WRITE, errp)) {
|
basic_flags | BLK_PERM_WRITE, errp)) {
|
||||||
bdrv_graph_wrunlock(bs);
|
bdrv_graph_wrunlock();
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,11 +389,11 @@ void stream_start(const char *job_id, BlockDriverState *bs,
|
|||||||
ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
|
ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
|
||||||
basic_flags, errp);
|
basic_flags, errp);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
bdrv_graph_wrunlock(bs);
|
bdrv_graph_wrunlock();
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bdrv_graph_wrunlock(bs);
|
bdrv_graph_wrunlock();
|
||||||
|
|
||||||
s->base_overlay = base_overlay;
|
s->base_overlay = base_overlay;
|
||||||
s->above_base = above_base;
|
s->above_base = above_base;
|
||||||
|
|||||||
38
block/vmdk.c
38
block/vmdk.c
@@ -283,7 +283,7 @@ static void vmdk_free_extents(BlockDriverState *bs)
|
|||||||
bdrv_unref_child(bs, e->file);
|
bdrv_unref_child(bs, e->file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bdrv_graph_wrunlock(NULL);
|
bdrv_graph_wrunlock();
|
||||||
|
|
||||||
g_free(s->extents);
|
g_free(s->extents);
|
||||||
}
|
}
|
||||||
@@ -351,41 +351,29 @@ vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
|
|||||||
BDRVVmdkState *s = bs->opaque;
|
BDRVVmdkState *s = bs->opaque;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
size_t desc_buf_size;
|
desc = g_malloc0(DESC_SIZE);
|
||||||
|
tmp_desc = g_malloc0(DESC_SIZE);
|
||||||
if (s->desc_offset == 0) {
|
ret = bdrv_co_pread(bs->file, s->desc_offset, DESC_SIZE, desc, 0);
|
||||||
desc_buf_size = bdrv_getlength(bs->file->bs);
|
|
||||||
if (desc_buf_size > 16ULL << 20) {
|
|
||||||
error_report("VMDK description file too big");
|
|
||||||
return -EFBIG;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
desc_buf_size = DESC_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
desc = g_malloc0(desc_buf_size);
|
|
||||||
tmp_desc = g_malloc0(desc_buf_size);
|
|
||||||
ret = bdrv_co_pread(bs->file, s->desc_offset, desc_buf_size, desc, 0);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
desc[desc_buf_size - 1] = '\0';
|
desc[DESC_SIZE - 1] = '\0';
|
||||||
tmp_str = strstr(desc, "parentCID");
|
tmp_str = strstr(desc, "parentCID");
|
||||||
if (tmp_str == NULL) {
|
if (tmp_str == NULL) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
pstrcpy(tmp_desc, desc_buf_size, tmp_str);
|
pstrcpy(tmp_desc, DESC_SIZE, tmp_str);
|
||||||
p_name = strstr(desc, "CID");
|
p_name = strstr(desc, "CID");
|
||||||
if (p_name != NULL) {
|
if (p_name != NULL) {
|
||||||
p_name += sizeof("CID");
|
p_name += sizeof("CID");
|
||||||
snprintf(p_name, desc_buf_size - (p_name - desc), "%" PRIx32 "\n", cid);
|
snprintf(p_name, DESC_SIZE - (p_name - desc), "%" PRIx32 "\n", cid);
|
||||||
pstrcat(desc, desc_buf_size, tmp_desc);
|
pstrcat(desc, DESC_SIZE, tmp_desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_co_pwrite_sync(bs->file, s->desc_offset, desc_buf_size, desc, 0);
|
ret = bdrv_co_pwrite_sync(bs->file, s->desc_offset, DESC_SIZE, desc, 0);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
g_free(desc);
|
g_free(desc);
|
||||||
@@ -1249,7 +1237,7 @@ vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
|
|||||||
bdrv_graph_rdunlock_main_loop();
|
bdrv_graph_rdunlock_main_loop();
|
||||||
bdrv_graph_wrlock(NULL);
|
bdrv_graph_wrlock(NULL);
|
||||||
bdrv_unref_child(bs, extent_file);
|
bdrv_unref_child(bs, extent_file);
|
||||||
bdrv_graph_wrunlock(NULL);
|
bdrv_graph_wrunlock();
|
||||||
bdrv_graph_rdlock_main_loop();
|
bdrv_graph_rdlock_main_loop();
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -1268,7 +1256,7 @@ vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
|
|||||||
bdrv_graph_rdunlock_main_loop();
|
bdrv_graph_rdunlock_main_loop();
|
||||||
bdrv_graph_wrlock(NULL);
|
bdrv_graph_wrlock(NULL);
|
||||||
bdrv_unref_child(bs, extent_file);
|
bdrv_unref_child(bs, extent_file);
|
||||||
bdrv_graph_wrunlock(NULL);
|
bdrv_graph_wrunlock();
|
||||||
bdrv_graph_rdlock_main_loop();
|
bdrv_graph_rdlock_main_loop();
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -1279,7 +1267,7 @@ vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
|
|||||||
bdrv_graph_rdunlock_main_loop();
|
bdrv_graph_rdunlock_main_loop();
|
||||||
bdrv_graph_wrlock(NULL);
|
bdrv_graph_wrlock(NULL);
|
||||||
bdrv_unref_child(bs, extent_file);
|
bdrv_unref_child(bs, extent_file);
|
||||||
bdrv_graph_wrunlock(NULL);
|
bdrv_graph_wrunlock();
|
||||||
bdrv_graph_rdlock_main_loop();
|
bdrv_graph_rdlock_main_loop();
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -1289,7 +1277,7 @@ vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
|
|||||||
bdrv_graph_rdunlock_main_loop();
|
bdrv_graph_rdunlock_main_loop();
|
||||||
bdrv_graph_wrlock(NULL);
|
bdrv_graph_wrlock(NULL);
|
||||||
bdrv_unref_child(bs, extent_file);
|
bdrv_unref_child(bs, extent_file);
|
||||||
bdrv_graph_wrunlock(NULL);
|
bdrv_graph_wrunlock();
|
||||||
bdrv_graph_rdlock_main_loop();
|
bdrv_graph_rdlock_main_loop();
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
goto out;
|
goto out;
|
||||||
|
|||||||
@@ -1613,7 +1613,7 @@ static void external_snapshot_abort(void *opaque)
|
|||||||
bdrv_drained_begin(state->new_bs);
|
bdrv_drained_begin(state->new_bs);
|
||||||
bdrv_graph_wrlock(state->old_bs);
|
bdrv_graph_wrlock(state->old_bs);
|
||||||
bdrv_replace_node(state->new_bs, state->old_bs, &error_abort);
|
bdrv_replace_node(state->new_bs, state->old_bs, &error_abort);
|
||||||
bdrv_graph_wrunlock(state->old_bs);
|
bdrv_graph_wrunlock();
|
||||||
bdrv_drained_end(state->new_bs);
|
bdrv_drained_end(state->new_bs);
|
||||||
|
|
||||||
bdrv_unref(state->old_bs); /* bdrv_replace_node() ref'ed old_bs */
|
bdrv_unref(state->old_bs); /* bdrv_replace_node() ref'ed old_bs */
|
||||||
@@ -2400,9 +2400,8 @@ void coroutine_fn qmp_block_resize(const char *device, const char *node_name,
|
|||||||
|
|
||||||
bdrv_co_lock(bs);
|
bdrv_co_lock(bs);
|
||||||
bdrv_drained_end(bs);
|
bdrv_drained_end(bs);
|
||||||
bdrv_co_unlock(bs);
|
|
||||||
|
|
||||||
blk_co_unref(blk);
|
blk_co_unref(blk);
|
||||||
|
bdrv_co_unlock(bs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void qmp_block_stream(const char *job_id, const char *device,
|
void qmp_block_stream(const char *job_id, const char *device,
|
||||||
@@ -3693,7 +3692,7 @@ void qmp_x_blockdev_change(const char *parent, const char *child,
|
|||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
bdrv_graph_wrunlock(NULL);
|
bdrv_graph_wrunlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockJobInfoList *qmp_query_block_jobs(Error **errp)
|
BlockJobInfoList *qmp_query_block_jobs(Error **errp)
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ void block_job_remove_all_bdrv(BlockJob *job)
|
|||||||
|
|
||||||
g_slist_free_1(l);
|
g_slist_free_1(l);
|
||||||
}
|
}
|
||||||
bdrv_graph_wrunlock_ctx(job->job.aio_context);
|
bdrv_graph_wrunlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool block_job_has_bdrv(BlockJob *job, BlockDriverState *bs)
|
bool block_job_has_bdrv(BlockJob *job, BlockDriverState *bs)
|
||||||
@@ -523,7 +523,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
|
|||||||
job = job_create(job_id, &driver->job_driver, txn, bdrv_get_aio_context(bs),
|
job = job_create(job_id, &driver->job_driver, txn, bdrv_get_aio_context(bs),
|
||||||
flags, cb, opaque, errp);
|
flags, cb, opaque, errp);
|
||||||
if (job == NULL) {
|
if (job == NULL) {
|
||||||
bdrv_graph_wrunlock(bs);
|
bdrv_graph_wrunlock();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -563,11 +563,11 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
bdrv_graph_wrunlock(bs);
|
bdrv_graph_wrunlock();
|
||||||
return job;
|
return job;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
bdrv_graph_wrunlock(bs);
|
bdrv_graph_wrunlock();
|
||||||
job_early_fail(&job->job);
|
job_early_fail(&job->job);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ static inline abi_long do_obreak(abi_ulong brk_val)
|
|||||||
return target_brk;
|
return target_brk;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Release heap if necessary */
|
/* Release heap if necesary */
|
||||||
if (new_brk < old_brk) {
|
if (new_brk < old_brk) {
|
||||||
target_munmap(new_brk, old_brk - new_brk);
|
target_munmap(new_brk, old_brk - new_brk);
|
||||||
|
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
|
|||||||
}
|
}
|
||||||
|
|
||||||
qarg0 = argp = g_new0(char *, argc + 9);
|
qarg0 = argp = g_new0(char *, argc + 9);
|
||||||
/* save the first argument for the emulator */
|
/* save the first agrument for the emulator */
|
||||||
*argp++ = (char *)getprogname();
|
*argp++ = (char *)getprogname();
|
||||||
qargp = argp;
|
qargp = argp;
|
||||||
*argp++ = (char *)getprogname();
|
*argp++ = (char *)getprogname();
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ static inline abi_long do_freebsd_fstatat(abi_long arg1, abi_long arg2,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* undocumented nstat(char *path, struct nstat *ub) syscall */
|
/* undocummented nstat(char *path, struct nstat *ub) syscall */
|
||||||
static abi_long do_freebsd11_nstat(abi_long arg1, abi_long arg2)
|
static abi_long do_freebsd11_nstat(abi_long arg1, abi_long arg2)
|
||||||
{
|
{
|
||||||
abi_long ret;
|
abi_long ret;
|
||||||
@@ -162,7 +162,7 @@ static abi_long do_freebsd11_nstat(abi_long arg1, abi_long arg2)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* undocumented nfstat(int fd, struct nstat *sb) syscall */
|
/* undocummented nfstat(int fd, struct nstat *sb) syscall */
|
||||||
static abi_long do_freebsd11_nfstat(abi_long arg1, abi_long arg2)
|
static abi_long do_freebsd11_nfstat(abi_long arg1, abi_long arg2)
|
||||||
{
|
{
|
||||||
abi_long ret;
|
abi_long ret;
|
||||||
@@ -175,7 +175,7 @@ static abi_long do_freebsd11_nfstat(abi_long arg1, abi_long arg2)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* undocumented nlstat(char *path, struct nstat *ub) syscall */
|
/* undocummented nlstat(char *path, struct nstat *ub) syscall */
|
||||||
static abi_long do_freebsd11_nlstat(abi_long arg1, abi_long arg2)
|
static abi_long do_freebsd11_nlstat(abi_long arg1, abi_long arg2)
|
||||||
{
|
{
|
||||||
abi_long ret;
|
abi_long ret;
|
||||||
|
|||||||
@@ -518,7 +518,7 @@ static const ChardevClass *char_get_class(const char *driver, Error **errp)
|
|||||||
|
|
||||||
if (object_class_is_abstract(oc)) {
|
if (object_class_is_abstract(oc)) {
|
||||||
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver",
|
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver",
|
||||||
"a non-abstract device type");
|
"an abstract device type");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#CONFIG_QXL=n
|
#CONFIG_QXL=n
|
||||||
#CONFIG_SEV=n
|
#CONFIG_SEV=n
|
||||||
#CONFIG_SGA=n
|
#CONFIG_SGA=n
|
||||||
|
#CONFIG_TDX=n
|
||||||
#CONFIG_TEST_DEVICES=n
|
#CONFIG_TEST_DEVICES=n
|
||||||
#CONFIG_TPM_CRB=n
|
#CONFIG_TPM_CRB=n
|
||||||
#CONFIG_TPM_TIS_ISA=n
|
#CONFIG_TPM_TIS_ISA=n
|
||||||
|
|||||||
28
configure
vendored
28
configure
vendored
@@ -41,7 +41,12 @@ then
|
|||||||
# This file is auto-generated by configure to support in-source tree
|
# This file is auto-generated by configure to support in-source tree
|
||||||
# 'make' command invocation
|
# 'make' command invocation
|
||||||
|
|
||||||
build:
|
ifeq ($(MAKECMDGOALS),)
|
||||||
|
recurse: all
|
||||||
|
endif
|
||||||
|
|
||||||
|
.NOTPARALLEL: %
|
||||||
|
%: force
|
||||||
@echo 'changing dir to build for $(MAKE) "$(MAKECMDGOALS)"...'
|
@echo 'changing dir to build for $(MAKE) "$(MAKECMDGOALS)"...'
|
||||||
@$(MAKE) -C build -f Makefile $(MAKECMDGOALS)
|
@$(MAKE) -C build -f Makefile $(MAKECMDGOALS)
|
||||||
@if test "$(MAKECMDGOALS)" = "distclean" && \
|
@if test "$(MAKECMDGOALS)" = "distclean" && \
|
||||||
@@ -49,9 +54,8 @@ build:
|
|||||||
then \
|
then \
|
||||||
rm -rf build GNUmakefile ; \
|
rm -rf build GNUmakefile ; \
|
||||||
fi
|
fi
|
||||||
%: build
|
force: ;
|
||||||
@
|
.PHONY: force
|
||||||
.PHONY: build
|
|
||||||
GNUmakefile: ;
|
GNUmakefile: ;
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
@@ -964,14 +968,14 @@ meson="$(cd pyvenv/bin; pwd)/meson"
|
|||||||
|
|
||||||
# Conditionally ensure Sphinx is installed.
|
# Conditionally ensure Sphinx is installed.
|
||||||
|
|
||||||
mkvenv_online_flag=""
|
mkvenv_flags=""
|
||||||
if test "$download" = "enabled" ; then
|
if test "$download" = "enabled" -a "$docs" = "enabled" ; then
|
||||||
mkvenv_online_flag=" --online"
|
mkvenv_flags="--online"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test "$docs" != "disabled" ; then
|
if test "$docs" != "disabled" ; then
|
||||||
if ! $mkvenv ensuregroup \
|
if ! $mkvenv ensuregroup \
|
||||||
$(test "$docs" = "enabled" && echo "$mkvenv_online_flag") \
|
$mkvenv_flags \
|
||||||
${source_path}/pythondeps.toml docs;
|
${source_path}/pythondeps.toml docs;
|
||||||
then
|
then
|
||||||
if test "$docs" = "enabled" ; then
|
if test "$docs" = "enabled" ; then
|
||||||
@@ -1303,8 +1307,8 @@ probe_target_compiler() {
|
|||||||
container_cross_cc=${container_cross_prefix}gcc
|
container_cross_cc=${container_cross_prefix}gcc
|
||||||
;;
|
;;
|
||||||
i386)
|
i386)
|
||||||
container_image=debian-i686-cross
|
container_image=fedora-i386-cross
|
||||||
container_cross_prefix=i686-linux-gnu-
|
container_cross_prefix=
|
||||||
;;
|
;;
|
||||||
loongarch64)
|
loongarch64)
|
||||||
container_image=debian-loongarch-cross
|
container_image=debian-loongarch-cross
|
||||||
@@ -1387,8 +1391,6 @@ probe_target_compiler() {
|
|||||||
done
|
done
|
||||||
|
|
||||||
try=cross
|
try=cross
|
||||||
# For softmmu/roms also look for a bi-endian or multilib-enabled host compiler
|
|
||||||
if [ "${1%softmmu}" != "$1" ] || test "$target_arch" = "$cpu"; then
|
|
||||||
case "$target_arch:$cpu" in
|
case "$target_arch:$cpu" in
|
||||||
aarch64_be:aarch64 | \
|
aarch64_be:aarch64 | \
|
||||||
armeb:arm | \
|
armeb:arm | \
|
||||||
@@ -1399,7 +1401,6 @@ probe_target_compiler() {
|
|||||||
"$cpu:$cpu")
|
"$cpu:$cpu")
|
||||||
try='native cross' ;;
|
try='native cross' ;;
|
||||||
esac
|
esac
|
||||||
fi
|
|
||||||
eval "target_cflags=\${cross_cc_cflags_$target_arch}"
|
eval "target_cflags=\${cross_cc_cflags_$target_arch}"
|
||||||
for thistry in $try; do
|
for thistry in $try; do
|
||||||
case $thistry in
|
case $thistry in
|
||||||
@@ -1630,7 +1631,6 @@ if test "$container" != no; then
|
|||||||
fi
|
fi
|
||||||
echo "SUBDIRS=$subdirs" >> $config_host_mak
|
echo "SUBDIRS=$subdirs" >> $config_host_mak
|
||||||
echo "PYTHON=$python" >> $config_host_mak
|
echo "PYTHON=$python" >> $config_host_mak
|
||||||
echo "MKVENV_ENSUREGROUP=$mkvenv ensuregroup $mkvenv_online_flag" >> $config_host_mak
|
|
||||||
echo "GENISOIMAGE=$genisoimage" >> $config_host_mak
|
echo "GENISOIMAGE=$genisoimage" >> $config_host_mak
|
||||||
echo "MESON=$meson" >> $config_host_mak
|
echo "MESON=$meson" >> $config_host_mak
|
||||||
echo "NINJA=$ninja" >> $config_host_mak
|
echo "NINJA=$ninja" >> $config_host_mak
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ all: $(SONAMES)
|
|||||||
$(CC) $(CFLAGS) $(PLUGIN_CFLAGS) -c -o $@ $<
|
$(CC) $(CFLAGS) $(PLUGIN_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
ifeq ($(CONFIG_WIN32),y)
|
ifeq ($(CONFIG_WIN32),y)
|
||||||
lib%$(SO_SUFFIX): %.o win32_linker.o ../../plugins/libqemu_plugin_api.a
|
lib%$(SO_SUFFIX): %.o win32_linker.o ../../plugins/qemu_plugin_api.lib
|
||||||
$(CC) -shared -o $@ $^ $(LDLIBS)
|
$(CC) -shared -o $@ $^ $(LDLIBS)
|
||||||
else ifeq ($(CONFIG_DARWIN),y)
|
else ifeq ($(CONFIG_DARWIN),y)
|
||||||
lib%$(SO_SUFFIX): %.o
|
lib%$(SO_SUFFIX): %.o
|
||||||
|
|||||||
@@ -401,7 +401,7 @@ virgl_cmd_set_scanout(VuGpu *g,
|
|||||||
|
|
||||||
if (g->use_modifiers) {
|
if (g->use_modifiers) {
|
||||||
/*
|
/*
|
||||||
* The message uses all the fields set in dmabuf_scanout plus
|
* The mesage uses all the fields set in dmabuf_scanout plus
|
||||||
* modifiers which is appended after VhostUserGpuDMABUFScanout.
|
* modifiers which is appended after VhostUserGpuDMABUFScanout.
|
||||||
*/
|
*/
|
||||||
msg.request = VHOST_USER_GPU_DMABUF_SCANOUT2;
|
msg.request = VHOST_USER_GPU_DMABUF_SCANOUT2;
|
||||||
|
|||||||
26
disas/cris.c
26
disas/cris.c
@@ -1731,10 +1731,10 @@ format_hex (unsigned long number,
|
|||||||
unsigned (== 0). */
|
unsigned (== 0). */
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
format_dec (long number, char *outbuffer, size_t outsize, int signedp)
|
format_dec (long number, char *outbuffer, int signedp)
|
||||||
{
|
{
|
||||||
last_immediate = number;
|
last_immediate = number;
|
||||||
snprintf (outbuffer, outsize, signedp ? "%ld" : "%lu", number);
|
sprintf (outbuffer, signedp ? "%ld" : "%lu", number);
|
||||||
|
|
||||||
return outbuffer + strlen (outbuffer);
|
return outbuffer + strlen (outbuffer);
|
||||||
}
|
}
|
||||||
@@ -1876,12 +1876,6 @@ print_flags (struct cris_disasm_data *disdata, unsigned int insn, char *cp)
|
|||||||
return cp;
|
return cp;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define FORMAT_DEC(number, tp, signedp) \
|
|
||||||
format_dec (number, tp, ({ \
|
|
||||||
assert(tp >= temp && tp <= temp + sizeof(temp)); \
|
|
||||||
temp + sizeof(temp) - tp; \
|
|
||||||
}), signedp)
|
|
||||||
|
|
||||||
/* Print out an insn with its operands, and update the info->insn_type
|
/* Print out an insn with its operands, and update the info->insn_type
|
||||||
fields. The prefix_opcodep and the rest hold a prefix insn that is
|
fields. The prefix_opcodep and the rest hold a prefix insn that is
|
||||||
supposed to be output as an address mode. */
|
supposed to be output as an address mode. */
|
||||||
@@ -2111,7 +2105,7 @@ print_with_operands (const struct cris_opcode *opcodep,
|
|||||||
if ((*cs == 'z' && (insn & 0x20))
|
if ((*cs == 'z' && (insn & 0x20))
|
||||||
|| (opcodep->match == BDAP_QUICK_OPCODE
|
|| (opcodep->match == BDAP_QUICK_OPCODE
|
||||||
&& (nbytes <= 2 || buffer[1 + nbytes] == 0)))
|
&& (nbytes <= 2 || buffer[1 + nbytes] == 0)))
|
||||||
tp = FORMAT_DEC (number, tp, signedp);
|
tp = format_dec (number, tp, signedp);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
unsigned int highbyte = (number >> 24) & 0xff;
|
unsigned int highbyte = (number >> 24) & 0xff;
|
||||||
@@ -2247,7 +2241,7 @@ print_with_operands (const struct cris_opcode *opcodep,
|
|||||||
with_reg_prefix);
|
with_reg_prefix);
|
||||||
if (number >= 0)
|
if (number >= 0)
|
||||||
*tp++ = '+';
|
*tp++ = '+';
|
||||||
tp = FORMAT_DEC (number, tp, 1);
|
tp = format_dec (number, tp, 1);
|
||||||
|
|
||||||
info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG;
|
info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG;
|
||||||
info->target = (prefix_insn >> 12) & 15;
|
info->target = (prefix_insn >> 12) & 15;
|
||||||
@@ -2346,7 +2340,7 @@ print_with_operands (const struct cris_opcode *opcodep,
|
|||||||
{
|
{
|
||||||
if (number >= 0)
|
if (number >= 0)
|
||||||
*tp++ = '+';
|
*tp++ = '+';
|
||||||
tp = FORMAT_DEC (number, tp, 1);
|
tp = format_dec (number, tp, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -2403,7 +2397,7 @@ print_with_operands (const struct cris_opcode *opcodep,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'I':
|
case 'I':
|
||||||
tp = FORMAT_DEC (insn & 63, tp, 0);
|
tp = format_dec (insn & 63, tp, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'b':
|
case 'b':
|
||||||
@@ -2432,11 +2426,11 @@ print_with_operands (const struct cris_opcode *opcodep,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'c':
|
case 'c':
|
||||||
tp = FORMAT_DEC (insn & 31, tp, 0);
|
tp = format_dec (insn & 31, tp, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'C':
|
case 'C':
|
||||||
tp = FORMAT_DEC (insn & 15, tp, 0);
|
tp = format_dec (insn & 15, tp, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'o':
|
case 'o':
|
||||||
@@ -2469,7 +2463,7 @@ print_with_operands (const struct cris_opcode *opcodep,
|
|||||||
if (number > 127)
|
if (number > 127)
|
||||||
number = number - 256;
|
number = number - 256;
|
||||||
|
|
||||||
tp = FORMAT_DEC (number, tp, 1);
|
tp = format_dec (number, tp, 1);
|
||||||
*tp++ = ',';
|
*tp++ = ',';
|
||||||
tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix);
|
tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix);
|
||||||
}
|
}
|
||||||
@@ -2480,7 +2474,7 @@ print_with_operands (const struct cris_opcode *opcodep,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'i':
|
case 'i':
|
||||||
tp = FORMAT_DEC ((insn & 32) ? (insn & 31) | ~31L : insn & 31, tp, 1);
|
tp = format_dec ((insn & 32) ? (insn & 31) | ~31L : insn & 31, tp, 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'P':
|
case 'P':
|
||||||
|
|||||||
@@ -1968,10 +1968,6 @@ print_insn_hppa (bfd_vma memaddr, disassemble_info *info)
|
|||||||
|
|
||||||
insn = bfd_getb32 (buffer);
|
insn = bfd_getb32 (buffer);
|
||||||
|
|
||||||
info->fprintf_func(info->stream, " %02x %02x %02x %02x ",
|
|
||||||
(insn >> 24) & 0xff, (insn >> 16) & 0xff,
|
|
||||||
(insn >> 8) & 0xff, insn & 0xff);
|
|
||||||
|
|
||||||
for (i = 0; i < NUMOPCODES; ++i)
|
for (i = 0; i < NUMOPCODES; ++i)
|
||||||
{
|
{
|
||||||
const struct pa_opcode *opcode = &pa_opcodes[i];
|
const struct pa_opcode *opcode = &pa_opcodes[i];
|
||||||
@@ -2830,6 +2826,6 @@ print_insn_hppa (bfd_vma memaddr, disassemble_info *info)
|
|||||||
return sizeof (insn);
|
return sizeof (insn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
info->fprintf_func(info->stream, "<unknown>");
|
(*info->fprintf_func) (info->stream, "#%8x", insn);
|
||||||
return sizeof (insn);
|
return sizeof (insn);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -236,16 +236,6 @@ it. Since all recent x86 hardware from the past >10 years is capable of the
|
|||||||
64-bit x86 extensions, a corresponding 64-bit OS should be used instead.
|
64-bit x86 extensions, a corresponding 64-bit OS should be used instead.
|
||||||
|
|
||||||
|
|
||||||
System emulator CPUs
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
Nios II CPU (since 8.2)
|
|
||||||
'''''''''''''''''''''''
|
|
||||||
|
|
||||||
The Nios II architecture is orphan. The ``nios2`` guest CPU support is
|
|
||||||
deprecated and will be removed in a future version of QEMU.
|
|
||||||
|
|
||||||
|
|
||||||
System emulator machines
|
System emulator machines
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
@@ -264,11 +254,6 @@ These old machine types are quite neglected nowadays and thus might have
|
|||||||
various pitfalls with regards to live migration. Use a newer machine type
|
various pitfalls with regards to live migration. Use a newer machine type
|
||||||
instead.
|
instead.
|
||||||
|
|
||||||
Nios II ``10m50-ghrd`` and ``nios2-generic-nommu`` machines (since 8.2)
|
|
||||||
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
|
||||||
|
|
||||||
The Nios II architecture is orphan.
|
|
||||||
|
|
||||||
|
|
||||||
Backend options
|
Backend options
|
||||||
---------------
|
---------------
|
||||||
@@ -529,5 +514,5 @@ old compression method (since 8.2)
|
|||||||
|
|
||||||
Compression method fails too much. Too many races. We are going to
|
Compression method fails too much. Too many races. We are going to
|
||||||
remove it if nobody fixes it. For starters, migration-test
|
remove it if nobody fixes it. For starters, migration-test
|
||||||
compression tests are disabled because they fail randomly. If you need
|
compression tests are disabled becase they fail randomly. If you need
|
||||||
compression, use multifd compression methods.
|
compression, use multifd compression methods.
|
||||||
|
|||||||
@@ -129,9 +129,8 @@ causing most hypervisors to trap and fault on them.
|
|||||||
.. warning::
|
.. warning::
|
||||||
Semihosting inherently bypasses any isolation there may be between
|
Semihosting inherently bypasses any isolation there may be between
|
||||||
the guest and the host. As a result a program using semihosting can
|
the guest and the host. As a result a program using semihosting can
|
||||||
happily trash your host system. Some semihosting calls (e.g.
|
happily trash your host system. You should only ever run trusted
|
||||||
``SYS_READC``) can block execution indefinitely. You should only
|
code with semihosting enabled.
|
||||||
ever run trusted code with semihosting enabled.
|
|
||||||
|
|
||||||
Redirection
|
Redirection
|
||||||
~~~~~~~~~~~
|
~~~~~~~~~~~
|
||||||
|
|||||||
@@ -122,78 +122,10 @@ functioning. These are performed using a few more helper functions:
|
|||||||
indicated by $TMPC.
|
indicated by $TMPC.
|
||||||
|
|
||||||
|
|
||||||
Python virtual environments and the build process
|
Python virtual environments and the QEMU build system
|
||||||
-------------------------------------------------
|
-----------------------------------------------------
|
||||||
|
|
||||||
An important step in ``configure`` is to create a Python virtual
|
|
||||||
environment (venv) during the configuration phase. The Python interpreter
|
|
||||||
comes from the ``--python`` command line option, the ``$PYTHON`` variable
|
|
||||||
from the environment, or the system PATH, in this order. The venv resides
|
|
||||||
in the ``pyvenv`` directory in the build tree, and provides consistency
|
|
||||||
in how the build process runs Python code.
|
|
||||||
|
|
||||||
At this stage, ``configure`` also queries the chosen Python interpreter
|
|
||||||
about QEMU's build dependencies. Note that the build process does *not*
|
|
||||||
look for ``meson``, ``sphinx-build`` or ``avocado`` binaries in the PATH;
|
|
||||||
likewise, there are no options such as ``--meson`` or ``--sphinx-build``.
|
|
||||||
This avoids a potential mismatch, where Meson and Sphinx binaries on the
|
|
||||||
PATH might operate in a different Python environment than the one chosen
|
|
||||||
by the user during the build process. On the other hand, it introduces
|
|
||||||
a potential source of confusion where the user installs a dependency but
|
|
||||||
``configure`` is not able to find it. When this happens, the dependency
|
|
||||||
was installed in the ``site-packages`` directory of another interpreter,
|
|
||||||
or with the wrong ``pip`` program.
|
|
||||||
|
|
||||||
If a package is available for the chosen interpreter, ``configure``
|
|
||||||
prepares a small script that invokes it from the venv itself[#distlib]_.
|
|
||||||
If not, ``configure`` can also optionally install dependencies in the
|
|
||||||
virtual environment with ``pip``, either from wheels in ``python/wheels``
|
|
||||||
or by downloading the package with PyPI. Downloading can be disabled with
|
|
||||||
``--disable-download``; and anyway, it only happens when a ``configure``
|
|
||||||
option (currently, only ``--enable-docs``) is explicitly enabled but
|
|
||||||
the dependencies are not present[#pip]_.
|
|
||||||
|
|
||||||
.. [#distlib] The scripts are created based on the package's metadata,
|
|
||||||
specifically the ``console_script`` entry points. This is the
|
|
||||||
same mechanism that ``pip`` uses when installing a package.
|
|
||||||
Currently, in all cases it would be possible to use ``python -m``
|
|
||||||
instead of an entry point script, which makes this approach a
|
|
||||||
bit overkill. On the other hand, creating the scripts is
|
|
||||||
future proof and it makes the contents of the ``pyvenv/bin``
|
|
||||||
directory more informative. Portability is also not an issue,
|
|
||||||
because the Python Packaging Authority provides a package
|
|
||||||
``distlib.scripts`` to perform this task.
|
|
||||||
|
|
||||||
.. [#pip] ``pip`` might also be used when running ``make check-avocado``
|
|
||||||
if downloading is enabled, to ensure that Avocado is
|
|
||||||
available.
|
|
||||||
|
|
||||||
The required versions of the packages are stored in a configuration file
|
|
||||||
``pythondeps.toml``. The format is custom to QEMU, but it is documented
|
|
||||||
at the top of the file itself and it should be easy to understand. The
|
|
||||||
requirements should make it possible to use the version that is packaged
|
|
||||||
that is provided by supported distros.
|
|
||||||
|
|
||||||
When dependencies are downloaded, instead, ``configure`` uses a "known
|
|
||||||
good" version that is also listed in ``pythondeps.toml``. In this
|
|
||||||
scenario, ``pythondeps.toml`` behaves like the "lock file" used by
|
|
||||||
``cargo``, ``poetry`` or other dependency management systems.
|
|
||||||
|
|
||||||
|
|
||||||
Bundled Python packages
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
Python packages that are **mandatory** dependencies to build QEMU,
|
|
||||||
but are not available in all supported distros, are bundled with the
|
|
||||||
QEMU sources. Currently this includes Meson (outdated in CentOS 8
|
|
||||||
and derivatives, Ubuntu 20.04 and 22.04, and openSUSE Leap) and tomli
|
|
||||||
(absent in Ubuntu 20.04).
|
|
||||||
|
|
||||||
If you need to update these, please do so by modifying and rerunning
|
|
||||||
``python/scripts/vendor.py``. This script embeds the sha256 hash of
|
|
||||||
package sources and checks it. The pypi.org web site provides an easy
|
|
||||||
way to retrieve the sha256 hash of the sources.
|
|
||||||
|
|
||||||
|
TBD
|
||||||
|
|
||||||
Stage 2: Meson
|
Stage 2: Meson
|
||||||
==============
|
==============
|
||||||
@@ -444,15 +376,6 @@ This is needed to obey the --python= option passed to the configure
|
|||||||
script, which may point to something other than the first python3
|
script, which may point to something other than the first python3
|
||||||
binary on the path.
|
binary on the path.
|
||||||
|
|
||||||
By the time Meson runs, Python dependencies are available in the virtual
|
|
||||||
environment and should be invoked through the scripts that ``configure``
|
|
||||||
places under ``pyvenv``. One way to do so is as follows, using Meson's
|
|
||||||
``find_program`` function::
|
|
||||||
|
|
||||||
sphinx_build = find_program(
|
|
||||||
fs.parent(python.full_path()) / 'sphinx-build',
|
|
||||||
required: get_option('docs'))
|
|
||||||
|
|
||||||
|
|
||||||
Stage 3: Make
|
Stage 3: Make
|
||||||
=============
|
=============
|
||||||
@@ -511,11 +434,6 @@ number of dynamically created files listed later.
|
|||||||
executables. Build rules for various subdirectories are included in
|
executables. Build rules for various subdirectories are included in
|
||||||
other meson.build files spread throughout the QEMU source tree.
|
other meson.build files spread throughout the QEMU source tree.
|
||||||
|
|
||||||
``python/scripts/mkvenv.py``
|
|
||||||
A wrapper for the Python ``venv`` and ``distlib.scripts`` packages.
|
|
||||||
It handles creating the virtual environment, creating scripts in
|
|
||||||
``pyvenv/bin``, and calling ``pip`` to install dependencies.
|
|
||||||
|
|
||||||
``tests/Makefile.include``
|
``tests/Makefile.include``
|
||||||
Rules for external test harnesses. These include the TCG tests
|
Rules for external test harnesses. These include the TCG tests
|
||||||
and the Avocado-based integration tests.
|
and the Avocado-based integration tests.
|
||||||
|
|||||||
@@ -1061,7 +1061,7 @@ QEMU version, in this case pc-5.1.
|
|||||||
|
|
||||||
4 - qemu-5.1 -M pc-5.2 -> migrates to -> qemu-5.1 -M pc-5.2
|
4 - qemu-5.1 -M pc-5.2 -> migrates to -> qemu-5.1 -M pc-5.2
|
||||||
|
|
||||||
This combination is not possible as the qemu-5.1 doesn't understand
|
This combination is not possible as the qemu-5.1 doen't understand
|
||||||
pc-5.2 machine type. So nothing to worry here.
|
pc-5.2 machine type. So nothing to worry here.
|
||||||
|
|
||||||
Now it comes the interesting ones, when both QEMU processes are
|
Now it comes the interesting ones, when both QEMU processes are
|
||||||
@@ -1214,8 +1214,8 @@ machine types to have the right value::
|
|||||||
...
|
...
|
||||||
};
|
};
|
||||||
|
|
||||||
A device with different features on both sides
|
A device with diferent features on both sides
|
||||||
----------------------------------------------
|
---------------------------------------------
|
||||||
|
|
||||||
Let's assume that we are using the same QEMU binary on both sides,
|
Let's assume that we are using the same QEMU binary on both sides,
|
||||||
just to make the things easier. But we have a device that has
|
just to make the things easier. But we have a device that has
|
||||||
@@ -1294,12 +1294,12 @@ Host B:
|
|||||||
|
|
||||||
$ qemu-system-x86_64 -cpu host,taa-no=off
|
$ qemu-system-x86_64 -cpu host,taa-no=off
|
||||||
|
|
||||||
And you would be able to migrate between them. It is responsibility
|
And you would be able to migrate between them. It is responsability
|
||||||
of the management application or of the user to make sure that the
|
of the management application or of the user to make sure that the
|
||||||
configuration is correct. QEMU doesn't know how to look at this kind
|
configuration is correct. QEMU doesn't know how to look at this kind
|
||||||
of features in general.
|
of features in general.
|
||||||
|
|
||||||
Notice that we don't recommend to use -cpu host for migration. It is
|
Notice that we don't recomend to use -cpu host for migration. It is
|
||||||
used in this example because it makes the example simpler.
|
used in this example because it makes the example simpler.
|
||||||
|
|
||||||
Other devices have worse control about individual features. If they
|
Other devices have worse control about individual features. If they
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ have default values:
|
|||||||
-smp 1,drawers=3,books=3,sockets=2,cores=2,maxcpus=36 \
|
-smp 1,drawers=3,books=3,sockets=2,cores=2,maxcpus=36 \
|
||||||
-device z14-s390x-cpu,core-id=19,entitlement=high \
|
-device z14-s390x-cpu,core-id=19,entitlement=high \
|
||||||
-device z14-s390x-cpu,core-id=11,entitlement=low \
|
-device z14-s390x-cpu,core-id=11,entitlement=low \
|
||||||
-device z14-s390x-cpu,core-id=12,entitlement=high \
|
-device z14-s390x-cpu,core-id=112,entitlement=high \
|
||||||
...
|
...
|
||||||
|
|
||||||
Additions to query-cpus-fast
|
Additions to query-cpus-fast
|
||||||
@@ -78,7 +78,7 @@ modifiers for all configured vCPUs.
|
|||||||
"dedicated": true,
|
"dedicated": true,
|
||||||
"thread-id": 537005,
|
"thread-id": 537005,
|
||||||
"props": {
|
"props": {
|
||||||
"core-id": 12,
|
"core-id": 112,
|
||||||
"socket-id": 0,
|
"socket-id": 0,
|
||||||
"drawer-id": 3,
|
"drawer-id": 3,
|
||||||
"book-id": 2
|
"book-id": 2
|
||||||
@@ -86,7 +86,7 @@ modifiers for all configured vCPUs.
|
|||||||
"cpu-state": "operating",
|
"cpu-state": "operating",
|
||||||
"entitlement": "high",
|
"entitlement": "high",
|
||||||
"qom-path": "/machine/peripheral-anon/device[2]",
|
"qom-path": "/machine/peripheral-anon/device[2]",
|
||||||
"cpu-index": 12,
|
"cpu-index": 112,
|
||||||
"target": "s390x"
|
"target": "s390x"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -62,6 +62,12 @@ To deal with this case, when an I/O access is made we:
|
|||||||
- re-compile a single [1]_ instruction block for the current PC
|
- re-compile a single [1]_ instruction block for the current PC
|
||||||
- exit the cpu loop and execute the re-compiled block
|
- exit the cpu loop and execute the re-compiled block
|
||||||
|
|
||||||
|
The new block is created with the CF_LAST_IO compile flag which
|
||||||
|
ensures the final instruction translation starts with a call to
|
||||||
|
gen_io_start() so we don't enter a perpetual loop constantly
|
||||||
|
recompiling a single instruction block. For translators using the
|
||||||
|
common translator_loop this is done automatically.
|
||||||
|
|
||||||
.. [1] sometimes two instructions if dealing with delay slots
|
.. [1] sometimes two instructions if dealing with delay slots
|
||||||
|
|
||||||
Other I/O operations
|
Other I/O operations
|
||||||
|
|||||||
@@ -1016,7 +1016,7 @@ class. Here's a simple usage example:
|
|||||||
self.vm.launch()
|
self.vm.launch()
|
||||||
res = self.vm.cmd('human-monitor-command',
|
res = self.vm.cmd('human-monitor-command',
|
||||||
command_line='info version')
|
command_line='info version')
|
||||||
self.assertRegex(res, r'^(\d+\.\d+\.\d)')
|
self.assertRegexpMatches(res, r'^(\d+\.\d+\.\d)')
|
||||||
|
|
||||||
To execute your test, run:
|
To execute your test, run:
|
||||||
|
|
||||||
@@ -1077,7 +1077,7 @@ and hypothetical example follows:
|
|||||||
'human-monitor-command',
|
'human-monitor-command',
|
||||||
command_line='info version')
|
command_line='info version')
|
||||||
|
|
||||||
self.assertEqual(first_res, second_res, third_res)
|
self.assertEquals(first_res, second_res, third_res)
|
||||||
|
|
||||||
At test "tear down", ``avocado_qemu.Test`` handles all the QEMUMachines
|
At test "tear down", ``avocado_qemu.Test`` handles all the QEMUMachines
|
||||||
shutdown.
|
shutdown.
|
||||||
@@ -1371,33 +1371,23 @@ conditions. For example, tests that take longer to execute when QEMU is
|
|||||||
compiled with debug flags. Therefore, the ``AVOCADO_TIMEOUT_EXPECTED`` variable
|
compiled with debug flags. Therefore, the ``AVOCADO_TIMEOUT_EXPECTED`` variable
|
||||||
has been used to determine whether those tests should run or not.
|
has been used to determine whether those tests should run or not.
|
||||||
|
|
||||||
QEMU_TEST_FLAKY_TESTS
|
GITLAB_CI
|
||||||
^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^
|
||||||
Some tests are not working reliably and thus are disabled by default.
|
A number of tests are flagged to not run on the GitLab CI. Usually because
|
||||||
This includes tests that don't run reliably on GitLab's CI which
|
they proved to the flaky or there are constraints on the CI environment which
|
||||||
usually expose real issues that are rarely seen on developer machines
|
would make them fail. If you encounter a similar situation then use that
|
||||||
due to the constraints of the CI environment. If you encounter a
|
variable as shown on the code snippet below to skip the test:
|
||||||
similar situation then raise a bug and then mark the test as shown on
|
|
||||||
the code snippet below:
|
|
||||||
|
|
||||||
.. code::
|
.. code::
|
||||||
|
|
||||||
# See https://gitlab.com/qemu-project/qemu/-/issues/nnnn
|
@skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab')
|
||||||
@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
|
|
||||||
def test(self):
|
def test(self):
|
||||||
do_something()
|
do_something()
|
||||||
|
|
||||||
You can also add ``:avocado: tags=flaky`` to the test meta-data so
|
QEMU_TEST_FLAKY_TESTS
|
||||||
only the flaky tests can be run as a group:
|
^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
Some tests are not working reliably and thus are disabled by default.
|
||||||
.. code::
|
Set this environment variable to enable them.
|
||||||
|
|
||||||
env QEMU_TEST_FLAKY_TESTS=1 ./pyvenv/bin/avocado \
|
|
||||||
run tests/avocado -filter-by-tags=flaky
|
|
||||||
|
|
||||||
Tests should not live in this state forever and should either be fixed
|
|
||||||
or eventually removed.
|
|
||||||
|
|
||||||
|
|
||||||
Uninstalling Avocado
|
Uninstalling Avocado
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
sphinx==5.3.0
|
|
||||||
sphinx_rtd_theme==1.1.1
|
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
.. _tpm-device:
|
|
||||||
|
|
||||||
===============
|
===============
|
||||||
QEMU TPM Device
|
QEMU TPM Device
|
||||||
===============
|
===============
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ the following architecture extensions:
|
|||||||
- FEAT_PAN2 (AT S1E1R and AT S1E1W instruction variants affected by PSTATE.PAN)
|
- FEAT_PAN2 (AT S1E1R and AT S1E1W instruction variants affected by PSTATE.PAN)
|
||||||
- FEAT_PAN3 (Support for SCTLR_ELx.EPAN)
|
- FEAT_PAN3 (Support for SCTLR_ELx.EPAN)
|
||||||
- FEAT_PAuth (Pointer authentication)
|
- FEAT_PAuth (Pointer authentication)
|
||||||
- FEAT_PAuth2 (Enhancements to pointer authentication)
|
- FEAT_PAuth2 (Enhacements to pointer authentication)
|
||||||
- FEAT_PMULL (PMULL, PMULL2 instructions)
|
- FEAT_PMULL (PMULL, PMULL2 instructions)
|
||||||
- FEAT_PMUv3p1 (PMU Extensions v3.1)
|
- FEAT_PMUv3p1 (PMU Extensions v3.1)
|
||||||
- FEAT_PMUv3p4 (PMU Extensions v3.4)
|
- FEAT_PMUv3p4 (PMU Extensions v3.4)
|
||||||
|
|||||||
@@ -1,20 +1,16 @@
|
|||||||
Xen Device Emulation Backend (``xenpvh``)
|
XENPVH (``xenpvh``)
|
||||||
=========================================
|
=========================================
|
||||||
|
This machine creates a IOREQ server to register/connect with Xen Hypervisor.
|
||||||
|
|
||||||
This machine is a little unusual compared to others as QEMU just acts
|
When TPM is enabled, this machine also creates a tpm-tis-device at a user input
|
||||||
as an IOREQ server to register/connect with Xen Hypervisor. Control of
|
tpm base address, adds a TPM emulator and connects to a swtpm application
|
||||||
the VMs themselves is left to the Xen tooling.
|
running on host machine via chardev socket. This enables xenpvh to support TPM
|
||||||
|
functionalities for a guest domain.
|
||||||
|
|
||||||
When TPM is enabled, this machine also creates a tpm-tis-device at a
|
More information about TPM use and installing swtpm linux application can be
|
||||||
user input tpm base address, adds a TPM emulator and connects to a
|
found at: docs/specs/tpm.rst.
|
||||||
swtpm application running on host machine via chardev socket. This
|
|
||||||
enables xenpvh to support TPM functionalities for a guest domain.
|
|
||||||
|
|
||||||
More information about TPM use and installing swtpm linux application
|
|
||||||
can be found in the :ref:`tpm-device` section.
|
|
||||||
|
|
||||||
Example for starting swtpm on host machine:
|
Example for starting swtpm on host machine:
|
||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
mkdir /tmp/vtpm2
|
mkdir /tmp/vtpm2
|
||||||
@@ -22,7 +18,6 @@ Example for starting swtpm on host machine:
|
|||||||
--ctrl type=unixio,path=/tmp/vtpm2/swtpm-sock &
|
--ctrl type=unixio,path=/tmp/vtpm2/swtpm-sock &
|
||||||
|
|
||||||
Sample QEMU xenpvh commands for running and connecting with Xen:
|
Sample QEMU xenpvh commands for running and connecting with Xen:
|
||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
qemu-system-aarch64 -xen-domid 1 \
|
qemu-system-aarch64 -xen-domid 1 \
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ Supported mechanisms
|
|||||||
Currently supported confidential guest mechanisms are:
|
Currently supported confidential guest mechanisms are:
|
||||||
|
|
||||||
* AMD Secure Encrypted Virtualization (SEV) (see :doc:`i386/amd-memory-encryption`)
|
* AMD Secure Encrypted Virtualization (SEV) (see :doc:`i386/amd-memory-encryption`)
|
||||||
|
* Intel Trust Domain Extension (TDX) (see :doc:`i386/tdx`)
|
||||||
* POWER Protected Execution Facility (PEF) (see :ref:`power-papr-protected-execution-facility-pef`)
|
* POWER Protected Execution Facility (PEF) (see :ref:`power-papr-protected-execution-facility-pef`)
|
||||||
* s390x Protected Virtualization (PV) (see :doc:`s390x/protvirt`)
|
* s390x Protected Virtualization (PV) (see :doc:`s390x/protvirt`)
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ As TCG cannot track all memory accesses in user-mode there is no
|
|||||||
support for watchpoints.
|
support for watchpoints.
|
||||||
|
|
||||||
Relocating code
|
Relocating code
|
||||||
===============
|
---------------
|
||||||
|
|
||||||
On modern kernels confusion can be caused by code being relocated by
|
On modern kernels confusion can be caused by code being relocated by
|
||||||
features such as address space layout randomisation. To avoid
|
features such as address space layout randomisation. To avoid
|
||||||
@@ -68,17 +68,6 @@ confusion when debugging such things you either need to update gdb's
|
|||||||
view of where things are in memory or perhaps more trivially disable
|
view of where things are in memory or perhaps more trivially disable
|
||||||
ASLR when booting the system.
|
ASLR when booting the system.
|
||||||
|
|
||||||
Debugging user-space in system emulation
|
|
||||||
========================================
|
|
||||||
|
|
||||||
While it is technically possible to debug a user-space program running
|
|
||||||
inside a system image, it does present challenges. Kernel preemption
|
|
||||||
and execution mode changes between kernel and user mode can make it
|
|
||||||
hard to follow what's going on. Unless you are specifically trying to
|
|
||||||
debug some interaction between kernel and user-space you are better
|
|
||||||
off running your guest program with gdb either in the guest or using
|
|
||||||
a gdbserver exposed via a port to the outside world.
|
|
||||||
|
|
||||||
Debugging multicore machines
|
Debugging multicore machines
|
||||||
============================
|
============================
|
||||||
|
|
||||||
|
|||||||
113
docs/system/i386/tdx.rst
Normal file
113
docs/system/i386/tdx.rst
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
Intel Trusted Domain eXtension (TDX)
|
||||||
|
====================================
|
||||||
|
|
||||||
|
Intel Trusted Domain eXtensions (TDX) refers to an Intel technology that extends
|
||||||
|
Virtual Machine Extensions (VMX) and Multi-Key Total Memory Encryption (MKTME)
|
||||||
|
with a new kind of virtual machine guest called a Trust Domain (TD). A TD runs
|
||||||
|
in a CPU mode that is designed to protect the confidentiality of its memory
|
||||||
|
contents and its CPU state from any other software, including the hosting
|
||||||
|
Virtual Machine Monitor (VMM), unless explicitly shared by the TD itself.
|
||||||
|
|
||||||
|
Prerequisites
|
||||||
|
-------------
|
||||||
|
|
||||||
|
To run TD, the physical machine needs to have TDX module loaded and initialized
|
||||||
|
while KVM hypervisor has TDX support and has TDX enabled. If those requirements
|
||||||
|
are met, the ``KVM_CAP_VM_TYPES`` will report the support of ``KVM_X86_TDX_VM``.
|
||||||
|
|
||||||
|
Trust Domain Virtual Firmware (TDVF)
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Trust Domain Virtual Firmware (TDVF) is required to provide TD services to boot
|
||||||
|
TD Guest OS. TDVF needs to be copied to guest private memory and measured before
|
||||||
|
a TD boots.
|
||||||
|
|
||||||
|
The VM scope ``MEMORY_ENCRYPT_OP`` ioctl provides command ``KVM_TDX_INIT_MEM_REGION``
|
||||||
|
to copy the TDVF image to TD's private memory space.
|
||||||
|
|
||||||
|
Since TDX doesn't support readonly memslot, TDVF cannot be mapped as pflash
|
||||||
|
device and it actually works as RAM. "-bios" option is chosen to load TDVF.
|
||||||
|
|
||||||
|
OVMF is the opensource firmware that implements the TDVF support. Thus the
|
||||||
|
command line to specify and load TDVF is ``-bios OVMF.fd``
|
||||||
|
|
||||||
|
KVM private gmem
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
TD's memory (RAM) needs to be able to be transformed between private and shared.
|
||||||
|
And its BIOS (OVMF/TDVF) needs to be mapped as private. Thus QEMU needs to
|
||||||
|
allocate private gmem for them via KVM's IOCTL (KVM_CREATE_GUEST_MEMFD), which
|
||||||
|
requires KVM is newer enough that reports KVM_CAP_GUEST_MEMFD.
|
||||||
|
|
||||||
|
Feature Control
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Unlike non-TDX VM, the CPU features (enumerated by CPU or MSR) of a TD is not
|
||||||
|
under full control of VMM. VMM can only configure part of features of a TD on
|
||||||
|
``KVM_TDX_INIT_VM`` command of VM scope ``MEMORY_ENCRYPT_OP`` ioctl.
|
||||||
|
|
||||||
|
The configurable features have three types:
|
||||||
|
|
||||||
|
- Attributes:
|
||||||
|
- PKS (bit 30) controls whether Supervisor Protection Keys is exposed to TD,
|
||||||
|
which determines related CPUID bit and CR4 bit;
|
||||||
|
- PERFMON (bit 63) controls whether PMU is exposed to TD.
|
||||||
|
|
||||||
|
- XSAVE related features (XFAM):
|
||||||
|
XFAM is a 64b mask, which has the same format as XCR0 or IA32_XSS MSR. It
|
||||||
|
determines the set of extended features available for use by the guest TD.
|
||||||
|
|
||||||
|
- CPUID features:
|
||||||
|
Only some bits of some CPUID leaves are directly configurable by VMM.
|
||||||
|
|
||||||
|
What features can be configured is reported via TDX capabilities.
|
||||||
|
|
||||||
|
TDX capabilities
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The VM scope ``MEMORY_ENCRYPT_OP`` ioctl provides command ``KVM_TDX_CAPABILITIES``
|
||||||
|
to get the TDX capabilities from KVM. It returns a data structure of
|
||||||
|
``struct kvm_tdx_capabilites``, which tells the supported configuration of
|
||||||
|
attributes, XFAM and CPUIDs.
|
||||||
|
|
||||||
|
Launching a TD (TDX VM)
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
To launch a TDX guest, below are new added and required:
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
|qemu_system_x86| \\
|
||||||
|
-object tdx-guest,id=tdx0 \\
|
||||||
|
-machine ...,kernel-irqchip=split,confidential-guest-support=tdx0 \\
|
||||||
|
-bios OVMF.fd \\
|
||||||
|
|
||||||
|
Debugging
|
||||||
|
---------
|
||||||
|
|
||||||
|
Bit 0 of TD attributes, is DEBUG bit, which decides if the TD runs in off-TD
|
||||||
|
debug mode. When in off-TD debug mode, TD's VCPU state and private memory are
|
||||||
|
accessible via given SEAMCALLs. This requires KVM to expose APIs to invoke those
|
||||||
|
SEAMCALLs and resonponding QEMU change.
|
||||||
|
|
||||||
|
It's targeted as future work.
|
||||||
|
|
||||||
|
restrictions
|
||||||
|
------------
|
||||||
|
|
||||||
|
- kernel-irqchip must be split;
|
||||||
|
|
||||||
|
- No readonly support for private memory;
|
||||||
|
|
||||||
|
- No SMM support: SMM support requires manipulating the guset register states
|
||||||
|
which is not allowed;
|
||||||
|
|
||||||
|
Live Migration
|
||||||
|
--------------
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
References
|
||||||
|
----------
|
||||||
|
|
||||||
|
- `TDX Homepage <https://www.intel.com/content/www/us/en/developer/articles/technical/intel-trust-domain-extensions.html>`__
|
||||||
@@ -29,6 +29,7 @@ Architectural features
|
|||||||
i386/kvm-pv
|
i386/kvm-pv
|
||||||
i386/sgx
|
i386/sgx
|
||||||
i386/amd-memory-encryption
|
i386/amd-memory-encryption
|
||||||
|
i386/tdx
|
||||||
|
|
||||||
OS requirements
|
OS requirements
|
||||||
~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~
|
||||||
|
|||||||
@@ -692,7 +692,7 @@ static int gdb_handle_vcont(const char *p)
|
|||||||
/*
|
/*
|
||||||
* target_count and last_target keep track of how many CPUs we are going to
|
* target_count and last_target keep track of how many CPUs we are going to
|
||||||
* step or resume, and a pointer to the state structure of one of them,
|
* step or resume, and a pointer to the state structure of one of them,
|
||||||
* respectively
|
* respectivelly
|
||||||
*/
|
*/
|
||||||
int target_count = 0;
|
int target_count = 0;
|
||||||
CPUState *last_target = NULL;
|
CPUState *last_target = NULL;
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ enum {
|
|||||||
GDB_SIGNAL_TRAP = 5,
|
GDB_SIGNAL_TRAP = 5,
|
||||||
GDB_SIGNAL_ABRT = 6,
|
GDB_SIGNAL_ABRT = 6,
|
||||||
GDB_SIGNAL_ALRM = 14,
|
GDB_SIGNAL_ALRM = 14,
|
||||||
GDB_SIGNAL_STOP = 17,
|
|
||||||
GDB_SIGNAL_IO = 23,
|
GDB_SIGNAL_IO = 23,
|
||||||
GDB_SIGNAL_XCPU = 24,
|
GDB_SIGNAL_XCPU = 24,
|
||||||
GDB_SIGNAL_UNKNOWN = 143
|
GDB_SIGNAL_UNKNOWN = 143
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ static void gdb_vm_state_change(void *opaque, bool running, RunState state)
|
|||||||
break;
|
break;
|
||||||
case RUN_STATE_IO_ERROR:
|
case RUN_STATE_IO_ERROR:
|
||||||
trace_gdbstub_hit_io_error();
|
trace_gdbstub_hit_io_error();
|
||||||
ret = GDB_SIGNAL_STOP;
|
ret = GDB_SIGNAL_IO;
|
||||||
break;
|
break;
|
||||||
case RUN_STATE_WATCHDOG:
|
case RUN_STATE_WATCHDOG:
|
||||||
trace_gdbstub_hit_watchdog();
|
trace_gdbstub_hit_watchdog();
|
||||||
|
|||||||
@@ -947,7 +947,6 @@ static const VMStateDescription erst_vmstate = {
|
|||||||
|
|
||||||
static void erst_realizefn(PCIDevice *pci_dev, Error **errp)
|
static void erst_realizefn(PCIDevice *pci_dev, Error **errp)
|
||||||
{
|
{
|
||||||
ERRP_GUARD();
|
|
||||||
ERSTDeviceState *s = ACPIERST(pci_dev);
|
ERSTDeviceState *s = ACPIERST(pci_dev);
|
||||||
|
|
||||||
trace_acpi_erst_realizefn_in();
|
trace_acpi_erst_realizefn_in();
|
||||||
@@ -965,15 +964,9 @@ static void erst_realizefn(PCIDevice *pci_dev, Error **errp)
|
|||||||
|
|
||||||
/* HostMemoryBackend size will be multiple of PAGE_SIZE */
|
/* HostMemoryBackend size will be multiple of PAGE_SIZE */
|
||||||
s->storage_size = object_property_get_int(OBJECT(s->hostmem), "size", errp);
|
s->storage_size = object_property_get_int(OBJECT(s->hostmem), "size", errp);
|
||||||
if (*errp) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize backend storage and record_count */
|
/* Initialize backend storage and record_count */
|
||||||
check_erst_backend_storage(s, errp);
|
check_erst_backend_storage(s, errp);
|
||||||
if (*errp) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* BAR 0: Programming registers */
|
/* BAR 0: Programming registers */
|
||||||
memory_region_init_io(&s->iomem_mr, OBJECT(pci_dev), &erst_reg_ops, s,
|
memory_region_init_io(&s->iomem_mr, OBJECT(pci_dev), &erst_reg_ops, s,
|
||||||
@@ -984,9 +977,6 @@ static void erst_realizefn(PCIDevice *pci_dev, Error **errp)
|
|||||||
memory_region_init_ram(&s->exchange_mr, OBJECT(pci_dev),
|
memory_region_init_ram(&s->exchange_mr, OBJECT(pci_dev),
|
||||||
"erst.exchange",
|
"erst.exchange",
|
||||||
le32_to_cpu(s->header->record_size), errp);
|
le32_to_cpu(s->header->record_size), errp);
|
||||||
if (*errp) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY,
|
pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY,
|
||||||
&s->exchange_mr);
|
&s->exchange_mr);
|
||||||
|
|
||||||
|
|||||||
@@ -169,8 +169,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp)
|
|||||||
epit_table[i].irq));
|
epit_table[i].irq));
|
||||||
}
|
}
|
||||||
|
|
||||||
object_property_set_uint(OBJECT(&s->fec), "phy-num", s->phy_num,
|
object_property_set_uint(OBJECT(&s->fec), "phy-num", s->phy_num, &err);
|
||||||
&error_abort);
|
|
||||||
qdev_set_nic_properties(DEVICE(&s->fec), &nd_table[0]);
|
qdev_set_nic_properties(DEVICE(&s->fec), &nd_table[0]);
|
||||||
|
|
||||||
if (!sysbus_realize(SYS_BUS_DEVICE(&s->fec), errp)) {
|
if (!sysbus_realize(SYS_BUS_DEVICE(&s->fec), errp)) {
|
||||||
|
|||||||
@@ -379,8 +379,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
|
|||||||
spi_table[i].irq));
|
spi_table[i].irq));
|
||||||
}
|
}
|
||||||
|
|
||||||
object_property_set_uint(OBJECT(&s->eth), "phy-num", s->phy_num,
|
object_property_set_uint(OBJECT(&s->eth), "phy-num", s->phy_num, &err);
|
||||||
&error_abort);
|
|
||||||
qdev_set_nic_properties(DEVICE(&s->eth), &nd_table[0]);
|
qdev_set_nic_properties(DEVICE(&s->eth), &nd_table[0]);
|
||||||
if (!sysbus_realize(SYS_BUS_DEVICE(&s->eth), errp)) {
|
if (!sysbus_realize(SYS_BUS_DEVICE(&s->eth), errp)) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ static void netduino2_init(MachineState *machine)
|
|||||||
clock_set_hz(sysclk, SYSCLK_FRQ);
|
clock_set_hz(sysclk, SYSCLK_FRQ);
|
||||||
|
|
||||||
dev = qdev_new(TYPE_STM32F205_SOC);
|
dev = qdev_new(TYPE_STM32F205_SOC);
|
||||||
|
qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m3"));
|
||||||
qdev_connect_clock_in(dev, "sysclk", sysclk);
|
qdev_connect_clock_in(dev, "sysclk", sysclk);
|
||||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||||
|
|
||||||
@@ -53,14 +54,8 @@ static void netduino2_init(MachineState *machine)
|
|||||||
|
|
||||||
static void netduino2_machine_init(MachineClass *mc)
|
static void netduino2_machine_init(MachineClass *mc)
|
||||||
{
|
{
|
||||||
static const char * const valid_cpu_types[] = {
|
|
||||||
ARM_CPU_TYPE_NAME("cortex-m3"),
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
mc->desc = "Netduino 2 Machine (Cortex-M3)";
|
mc->desc = "Netduino 2 Machine (Cortex-M3)";
|
||||||
mc->init = netduino2_init;
|
mc->init = netduino2_init;
|
||||||
mc->valid_cpu_types = valid_cpu_types;
|
|
||||||
mc->ignore_memory_transaction_failures = true;
|
mc->ignore_memory_transaction_failures = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ static void netduinoplus2_init(MachineState *machine)
|
|||||||
clock_set_hz(sysclk, SYSCLK_FRQ);
|
clock_set_hz(sysclk, SYSCLK_FRQ);
|
||||||
|
|
||||||
dev = qdev_new(TYPE_STM32F405_SOC);
|
dev = qdev_new(TYPE_STM32F405_SOC);
|
||||||
|
qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m4"));
|
||||||
qdev_connect_clock_in(dev, "sysclk", sysclk);
|
qdev_connect_clock_in(dev, "sysclk", sysclk);
|
||||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||||
|
|
||||||
@@ -54,14 +55,8 @@ static void netduinoplus2_init(MachineState *machine)
|
|||||||
|
|
||||||
static void netduinoplus2_machine_init(MachineClass *mc)
|
static void netduinoplus2_machine_init(MachineClass *mc)
|
||||||
{
|
{
|
||||||
static const char * const valid_cpu_types[] = {
|
|
||||||
ARM_CPU_TYPE_NAME("cortex-m4"),
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
mc->desc = "Netduino Plus 2 Machine (Cortex-M4)";
|
mc->desc = "Netduino Plus 2 Machine (Cortex-M4)";
|
||||||
mc->init = netduinoplus2_init;
|
mc->init = netduinoplus2_init;
|
||||||
mc->valid_cpu_types = valid_cpu_types;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_MACHINE("netduinoplus2", netduinoplus2_machine_init)
|
DEFINE_MACHINE("netduinoplus2", netduinoplus2_machine_init)
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ static void olimex_stm32_h405_init(MachineState *machine)
|
|||||||
clock_set_hz(sysclk, SYSCLK_FRQ);
|
clock_set_hz(sysclk, SYSCLK_FRQ);
|
||||||
|
|
||||||
dev = qdev_new(TYPE_STM32F405_SOC);
|
dev = qdev_new(TYPE_STM32F405_SOC);
|
||||||
|
qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m4"));
|
||||||
qdev_connect_clock_in(dev, "sysclk", sysclk);
|
qdev_connect_clock_in(dev, "sysclk", sysclk);
|
||||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||||
|
|
||||||
@@ -57,14 +58,9 @@ static void olimex_stm32_h405_init(MachineState *machine)
|
|||||||
|
|
||||||
static void olimex_stm32_h405_machine_init(MachineClass *mc)
|
static void olimex_stm32_h405_machine_init(MachineClass *mc)
|
||||||
{
|
{
|
||||||
static const char * const valid_cpu_types[] = {
|
|
||||||
ARM_CPU_TYPE_NAME("cortex-m4"),
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
mc->desc = "Olimex STM32-H405 (Cortex-M4)";
|
mc->desc = "Olimex STM32-H405 (Cortex-M4)";
|
||||||
mc->init = olimex_stm32_h405_init;
|
mc->init = olimex_stm32_h405_init;
|
||||||
mc->valid_cpu_types = valid_cpu_types;
|
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m4");
|
||||||
|
|
||||||
/* SRAM pre-allocated as part of the SoC instantiation */
|
/* SRAM pre-allocated as part of the SoC instantiation */
|
||||||
mc->default_ram_size = 0;
|
mc->default_ram_size = 0;
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ static void stm32f100_soc_realize(DeviceState *dev_soc, Error **errp)
|
|||||||
/* Init ARMv7m */
|
/* Init ARMv7m */
|
||||||
armv7m = DEVICE(&s->armv7m);
|
armv7m = DEVICE(&s->armv7m);
|
||||||
qdev_prop_set_uint32(armv7m, "num-irq", 61);
|
qdev_prop_set_uint32(armv7m, "num-irq", 61);
|
||||||
qdev_prop_set_string(armv7m, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m3"));
|
qdev_prop_set_string(armv7m, "cpu-type", s->cpu_type);
|
||||||
qdev_prop_set_bit(armv7m, "enable-bitband", true);
|
qdev_prop_set_bit(armv7m, "enable-bitband", true);
|
||||||
qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk);
|
qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk);
|
||||||
qdev_connect_clock_in(armv7m, "refclk", s->refclk);
|
qdev_connect_clock_in(armv7m, "refclk", s->refclk);
|
||||||
@@ -180,12 +180,17 @@ static void stm32f100_soc_realize(DeviceState *dev_soc, Error **errp)
|
|||||||
create_unimplemented_device("CRC", 0x40023000, 0x400);
|
create_unimplemented_device("CRC", 0x40023000, 0x400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Property stm32f100_soc_properties[] = {
|
||||||
|
DEFINE_PROP_STRING("cpu-type", STM32F100State, cpu_type),
|
||||||
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
};
|
||||||
|
|
||||||
static void stm32f100_soc_class_init(ObjectClass *klass, void *data)
|
static void stm32f100_soc_class_init(ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
|
||||||
dc->realize = stm32f100_soc_realize;
|
dc->realize = stm32f100_soc_realize;
|
||||||
/* No vmstate or reset required: device has no internal state */
|
device_class_set_props(dc, stm32f100_soc_properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo stm32f100_soc_info = {
|
static const TypeInfo stm32f100_soc_info = {
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
|
|||||||
|
|
||||||
armv7m = DEVICE(&s->armv7m);
|
armv7m = DEVICE(&s->armv7m);
|
||||||
qdev_prop_set_uint32(armv7m, "num-irq", 96);
|
qdev_prop_set_uint32(armv7m, "num-irq", 96);
|
||||||
qdev_prop_set_string(armv7m, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m3"));
|
qdev_prop_set_string(armv7m, "cpu-type", s->cpu_type);
|
||||||
qdev_prop_set_bit(armv7m, "enable-bitband", true);
|
qdev_prop_set_bit(armv7m, "enable-bitband", true);
|
||||||
qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk);
|
qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk);
|
||||||
qdev_connect_clock_in(armv7m, "refclk", s->refclk);
|
qdev_connect_clock_in(armv7m, "refclk", s->refclk);
|
||||||
@@ -201,12 +201,17 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Property stm32f205_soc_properties[] = {
|
||||||
|
DEFINE_PROP_STRING("cpu-type", STM32F205State, cpu_type),
|
||||||
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
};
|
||||||
|
|
||||||
static void stm32f205_soc_class_init(ObjectClass *klass, void *data)
|
static void stm32f205_soc_class_init(ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
|
||||||
dc->realize = stm32f205_soc_realize;
|
dc->realize = stm32f205_soc_realize;
|
||||||
/* No vmstate or reset required: device has no internal state */
|
device_class_set_props(dc, stm32f205_soc_properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo stm32f205_soc_info = {
|
static const TypeInfo stm32f205_soc_info = {
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp)
|
|||||||
|
|
||||||
armv7m = DEVICE(&s->armv7m);
|
armv7m = DEVICE(&s->armv7m);
|
||||||
qdev_prop_set_uint32(armv7m, "num-irq", 96);
|
qdev_prop_set_uint32(armv7m, "num-irq", 96);
|
||||||
qdev_prop_set_string(armv7m, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m4"));
|
qdev_prop_set_string(armv7m, "cpu-type", s->cpu_type);
|
||||||
qdev_prop_set_bit(armv7m, "enable-bitband", true);
|
qdev_prop_set_bit(armv7m, "enable-bitband", true);
|
||||||
qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk);
|
qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk);
|
||||||
qdev_connect_clock_in(armv7m, "refclk", s->refclk);
|
qdev_connect_clock_in(armv7m, "refclk", s->refclk);
|
||||||
@@ -287,11 +287,17 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp)
|
|||||||
create_unimplemented_device("RNG", 0x50060800, 0x400);
|
create_unimplemented_device("RNG", 0x50060800, 0x400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Property stm32f405_soc_properties[] = {
|
||||||
|
DEFINE_PROP_STRING("cpu-type", STM32F405State, cpu_type),
|
||||||
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
};
|
||||||
|
|
||||||
static void stm32f405_soc_class_init(ObjectClass *klass, void *data)
|
static void stm32f405_soc_class_init(ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
|
||||||
dc->realize = stm32f405_soc_realize;
|
dc->realize = stm32f405_soc_realize;
|
||||||
|
device_class_set_props(dc, stm32f405_soc_properties);
|
||||||
/* No vmstate or reset required: device has no internal state */
|
/* No vmstate or reset required: device has no internal state */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ static void stm32vldiscovery_init(MachineState *machine)
|
|||||||
clock_set_hz(sysclk, SYSCLK_FRQ);
|
clock_set_hz(sysclk, SYSCLK_FRQ);
|
||||||
|
|
||||||
dev = qdev_new(TYPE_STM32F100_SOC);
|
dev = qdev_new(TYPE_STM32F100_SOC);
|
||||||
|
qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m3"));
|
||||||
qdev_connect_clock_in(dev, "sysclk", sysclk);
|
qdev_connect_clock_in(dev, "sysclk", sysclk);
|
||||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||||
|
|
||||||
@@ -57,14 +58,8 @@ static void stm32vldiscovery_init(MachineState *machine)
|
|||||||
|
|
||||||
static void stm32vldiscovery_machine_init(MachineClass *mc)
|
static void stm32vldiscovery_machine_init(MachineClass *mc)
|
||||||
{
|
{
|
||||||
static const char * const valid_cpu_types[] = {
|
|
||||||
ARM_CPU_TYPE_NAME("cortex-m3"),
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
mc->desc = "ST STM32VLDISCOVERY (Cortex-M3)";
|
mc->desc = "ST STM32VLDISCOVERY (Cortex-M3)";
|
||||||
mc->init = stm32vldiscovery_init;
|
mc->init = stm32vldiscovery_init;
|
||||||
mc->valid_cpu_types = valid_cpu_types;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_MACHINE("stm32vldiscovery", stm32vldiscovery_machine_init)
|
DEFINE_MACHINE("stm32vldiscovery", stm32vldiscovery_machine_init)
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
#include "hw/qdev-properties.h"
|
#include "hw/qdev-properties.h"
|
||||||
#include "intel-hda.h"
|
#include "intel-hda.h"
|
||||||
#include "migration/vmstate.h"
|
#include "migration/vmstate.h"
|
||||||
#include "qemu/host-utils.h"
|
|
||||||
#include "qemu/module.h"
|
#include "qemu/module.h"
|
||||||
#include "intel-hda-defs.h"
|
#include "intel-hda-defs.h"
|
||||||
#include "audio/audio.h"
|
#include "audio/audio.h"
|
||||||
@@ -190,9 +189,9 @@ struct HDAAudioState {
|
|||||||
bool use_timer;
|
bool use_timer;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline uint32_t hda_bytes_per_second(HDAAudioStream *st)
|
static inline int64_t hda_bytes_per_second(HDAAudioStream *st)
|
||||||
{
|
{
|
||||||
return 2 * (uint32_t)st->as.nchannels * (uint32_t)st->as.freq;
|
return 2LL * st->as.nchannels * st->as.freq;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void hda_timer_sync_adjust(HDAAudioStream *st, int64_t target_pos)
|
static inline void hda_timer_sync_adjust(HDAAudioStream *st, int64_t target_pos)
|
||||||
@@ -223,18 +222,12 @@ static void hda_audio_input_timer(void *opaque)
|
|||||||
|
|
||||||
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||||
|
|
||||||
int64_t uptime = now - st->buft_start;
|
int64_t buft_start = st->buft_start;
|
||||||
int64_t wpos = st->wpos;
|
int64_t wpos = st->wpos;
|
||||||
int64_t rpos = st->rpos;
|
int64_t rpos = st->rpos;
|
||||||
int64_t wanted_rpos;
|
|
||||||
|
|
||||||
if (uptime <= 0) {
|
int64_t wanted_rpos = hda_bytes_per_second(st) * (now - buft_start)
|
||||||
/* wanted_rpos <= 0 */
|
/ NANOSECONDS_PER_SECOND;
|
||||||
goto out_timer;
|
|
||||||
}
|
|
||||||
|
|
||||||
wanted_rpos = muldiv64(uptime, hda_bytes_per_second(st),
|
|
||||||
NANOSECONDS_PER_SECOND);
|
|
||||||
wanted_rpos &= -4; /* IMPORTANT! clip to frames */
|
wanted_rpos &= -4; /* IMPORTANT! clip to frames */
|
||||||
|
|
||||||
if (wanted_rpos <= rpos) {
|
if (wanted_rpos <= rpos) {
|
||||||
@@ -293,18 +286,12 @@ static void hda_audio_output_timer(void *opaque)
|
|||||||
|
|
||||||
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||||
|
|
||||||
int64_t uptime = now - st->buft_start;
|
int64_t buft_start = st->buft_start;
|
||||||
int64_t wpos = st->wpos;
|
int64_t wpos = st->wpos;
|
||||||
int64_t rpos = st->rpos;
|
int64_t rpos = st->rpos;
|
||||||
int64_t wanted_wpos;
|
|
||||||
|
|
||||||
if (uptime <= 0) {
|
int64_t wanted_wpos = hda_bytes_per_second(st) * (now - buft_start)
|
||||||
/* wanted_wpos <= 0 */
|
/ NANOSECONDS_PER_SECOND;
|
||||||
goto out_timer;
|
|
||||||
}
|
|
||||||
|
|
||||||
wanted_wpos = muldiv64(uptime, hda_bytes_per_second(st),
|
|
||||||
NANOSECONDS_PER_SECOND);
|
|
||||||
wanted_wpos &= -4; /* IMPORTANT! clip to frames */
|
wanted_wpos &= -4; /* IMPORTANT! clip to frames */
|
||||||
|
|
||||||
if (wanted_wpos <= wpos) {
|
if (wanted_wpos <= wpos) {
|
||||||
@@ -868,10 +855,10 @@ static Property hda_audio_properties[] = {
|
|||||||
static void hda_audio_init_output(HDACodecDevice *hda, Error **errp)
|
static void hda_audio_init_output(HDACodecDevice *hda, Error **errp)
|
||||||
{
|
{
|
||||||
HDAAudioState *a = HDA_AUDIO(hda);
|
HDAAudioState *a = HDA_AUDIO(hda);
|
||||||
const struct desc_codec *desc = &output_mixemu;
|
const struct desc_codec *desc = &output_nomixemu;
|
||||||
|
|
||||||
if (!a->mixer) {
|
if (!a->mixer) {
|
||||||
desc = &output_nomixemu;
|
desc = &output_mixemu;
|
||||||
}
|
}
|
||||||
|
|
||||||
hda_audio_init(hda, desc, errp);
|
hda_audio_init(hda, desc, errp);
|
||||||
@@ -880,10 +867,10 @@ static void hda_audio_init_output(HDACodecDevice *hda, Error **errp)
|
|||||||
static void hda_audio_init_duplex(HDACodecDevice *hda, Error **errp)
|
static void hda_audio_init_duplex(HDACodecDevice *hda, Error **errp)
|
||||||
{
|
{
|
||||||
HDAAudioState *a = HDA_AUDIO(hda);
|
HDAAudioState *a = HDA_AUDIO(hda);
|
||||||
const struct desc_codec *desc = &duplex_mixemu;
|
const struct desc_codec *desc = &duplex_nomixemu;
|
||||||
|
|
||||||
if (!a->mixer) {
|
if (!a->mixer) {
|
||||||
desc = &duplex_nomixemu;
|
desc = &duplex_mixemu;
|
||||||
}
|
}
|
||||||
|
|
||||||
hda_audio_init(hda, desc, errp);
|
hda_audio_init(hda, desc, errp);
|
||||||
@@ -892,10 +879,10 @@ static void hda_audio_init_duplex(HDACodecDevice *hda, Error **errp)
|
|||||||
static void hda_audio_init_micro(HDACodecDevice *hda, Error **errp)
|
static void hda_audio_init_micro(HDACodecDevice *hda, Error **errp)
|
||||||
{
|
{
|
||||||
HDAAudioState *a = HDA_AUDIO(hda);
|
HDAAudioState *a = HDA_AUDIO(hda);
|
||||||
const struct desc_codec *desc = µ_mixemu;
|
const struct desc_codec *desc = µ_nomixemu;
|
||||||
|
|
||||||
if (!a->mixer) {
|
if (!a->mixer) {
|
||||||
desc = µ_nomixemu;
|
desc = µ_mixemu;
|
||||||
}
|
}
|
||||||
|
|
||||||
hda_audio_init(hda, desc, errp);
|
hda_audio_init(hda, desc, errp);
|
||||||
|
|||||||
@@ -211,14 +211,14 @@ static void out_cb(void *opaque, int avail)
|
|||||||
AUD_set_active_out(s->vo, 0);
|
AUD_set_active_out(s->vo, 0);
|
||||||
}
|
}
|
||||||
if (c->type & STAT_EOL) {
|
if (c->type & STAT_EOL) {
|
||||||
via_isa_set_irq(&s->dev, 0, 1);
|
pci_set_irq(&s->dev, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (CLEN_IS_FLAG(c)) {
|
if (CLEN_IS_FLAG(c)) {
|
||||||
c->stat |= STAT_FLAG;
|
c->stat |= STAT_FLAG;
|
||||||
c->stat |= STAT_PAUSED;
|
c->stat |= STAT_PAUSED;
|
||||||
if (c->type & STAT_FLAG) {
|
if (c->type & STAT_FLAG) {
|
||||||
via_isa_set_irq(&s->dev, 0, 1);
|
pci_set_irq(&s->dev, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (CLEN_IS_STOP(c)) {
|
if (CLEN_IS_STOP(c)) {
|
||||||
@@ -305,13 +305,13 @@ static void sgd_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
|
|||||||
if (val & STAT_EOL) {
|
if (val & STAT_EOL) {
|
||||||
s->aur.stat &= ~(STAT_EOL | STAT_PAUSED);
|
s->aur.stat &= ~(STAT_EOL | STAT_PAUSED);
|
||||||
if (s->aur.type & STAT_EOL) {
|
if (s->aur.type & STAT_EOL) {
|
||||||
via_isa_set_irq(&s->dev, 0, 0);
|
pci_set_irq(&s->dev, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (val & STAT_FLAG) {
|
if (val & STAT_FLAG) {
|
||||||
s->aur.stat &= ~(STAT_FLAG | STAT_PAUSED);
|
s->aur.stat &= ~(STAT_FLAG | STAT_PAUSED);
|
||||||
if (s->aur.type & STAT_FLAG) {
|
if (s->aur.type & STAT_FLAG) {
|
||||||
via_isa_set_irq(&s->dev, 0, 0);
|
pci_set_irq(&s->dev, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -47,14 +47,12 @@ static void virtio_snd_pci_class_init(ObjectClass *klass, void *data)
|
|||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass);
|
VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass);
|
||||||
PCIDeviceClass *pcidevklass = PCI_DEVICE_CLASS(klass);
|
|
||||||
|
|
||||||
device_class_set_props(dc, virtio_snd_pci_properties);
|
device_class_set_props(dc, virtio_snd_pci_properties);
|
||||||
dc->desc = "Virtio Sound";
|
dc->desc = "Virtio Sound";
|
||||||
set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
|
set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
|
||||||
|
|
||||||
vpciklass->realize = virtio_snd_pci_realize;
|
vpciklass->realize = virtio_snd_pci_realize;
|
||||||
pcidevklass->class_id = PCI_CLASS_MULTIMEDIA_AUDIO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virtio_snd_pci_instance_init(Object *obj)
|
static void virtio_snd_pci_instance_init(Object *obj)
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ static void virtio_snd_pcm_out_cb(void *data, int available);
|
|||||||
static void virtio_snd_process_cmdq(VirtIOSound *s);
|
static void virtio_snd_process_cmdq(VirtIOSound *s);
|
||||||
static void virtio_snd_pcm_flush(VirtIOSoundPCMStream *stream);
|
static void virtio_snd_pcm_flush(VirtIOSoundPCMStream *stream);
|
||||||
static void virtio_snd_pcm_in_cb(void *data, int available);
|
static void virtio_snd_pcm_in_cb(void *data, int available);
|
||||||
static void virtio_snd_unrealize(DeviceState *dev);
|
|
||||||
|
|
||||||
static uint32_t supported_formats = BIT(VIRTIO_SND_PCM_FMT_S8)
|
static uint32_t supported_formats = BIT(VIRTIO_SND_PCM_FMT_S8)
|
||||||
| BIT(VIRTIO_SND_PCM_FMT_U8)
|
| BIT(VIRTIO_SND_PCM_FMT_U8)
|
||||||
@@ -69,7 +68,6 @@ static const VMStateDescription vmstate_virtio_snd_device = {
|
|||||||
|
|
||||||
static const VMStateDescription vmstate_virtio_snd = {
|
static const VMStateDescription vmstate_virtio_snd = {
|
||||||
.name = TYPE_VIRTIO_SND,
|
.name = TYPE_VIRTIO_SND,
|
||||||
.unmigratable = 1,
|
|
||||||
.minimum_version_id = VIRTIO_SOUND_VM_VERSION,
|
.minimum_version_id = VIRTIO_SOUND_VM_VERSION,
|
||||||
.version_id = VIRTIO_SOUND_VM_VERSION,
|
.version_id = VIRTIO_SOUND_VM_VERSION,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
@@ -1067,9 +1065,23 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
|
|||||||
virtio_snd_pcm_set_params default_params = { 0 };
|
virtio_snd_pcm_set_params default_params = { 0 };
|
||||||
uint32_t status;
|
uint32_t status;
|
||||||
|
|
||||||
|
vsnd->pcm = NULL;
|
||||||
|
vsnd->vmstate =
|
||||||
|
qemu_add_vm_change_state_handler(virtio_snd_vm_state_change, vsnd);
|
||||||
|
|
||||||
trace_virtio_snd_realize(vsnd);
|
trace_virtio_snd_realize(vsnd);
|
||||||
|
|
||||||
/* check number of jacks and streams */
|
vsnd->pcm = g_new0(VirtIOSoundPCM, 1);
|
||||||
|
vsnd->pcm->snd = vsnd;
|
||||||
|
vsnd->pcm->streams =
|
||||||
|
g_new0(VirtIOSoundPCMStream *, vsnd->snd_conf.streams);
|
||||||
|
vsnd->pcm->pcm_params =
|
||||||
|
g_new0(virtio_snd_pcm_set_params, vsnd->snd_conf.streams);
|
||||||
|
|
||||||
|
virtio_init(vdev, VIRTIO_ID_SOUND, sizeof(virtio_snd_config));
|
||||||
|
virtio_add_feature(&vsnd->features, VIRTIO_F_VERSION_1);
|
||||||
|
|
||||||
|
/* set number of jacks and streams */
|
||||||
if (vsnd->snd_conf.jacks > 8) {
|
if (vsnd->snd_conf.jacks > 8) {
|
||||||
error_setg(errp,
|
error_setg(errp,
|
||||||
"Invalid number of jacks: %"PRIu32,
|
"Invalid number of jacks: %"PRIu32,
|
||||||
@@ -1090,22 +1102,7 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!AUD_register_card("virtio-sound", &vsnd->card, errp)) {
|
AUD_register_card("virtio-sound", &vsnd->card, errp);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
vsnd->vmstate =
|
|
||||||
qemu_add_vm_change_state_handler(virtio_snd_vm_state_change, vsnd);
|
|
||||||
|
|
||||||
vsnd->pcm = g_new0(VirtIOSoundPCM, 1);
|
|
||||||
vsnd->pcm->snd = vsnd;
|
|
||||||
vsnd->pcm->streams =
|
|
||||||
g_new0(VirtIOSoundPCMStream *, vsnd->snd_conf.streams);
|
|
||||||
vsnd->pcm->pcm_params =
|
|
||||||
g_new0(virtio_snd_pcm_set_params, vsnd->snd_conf.streams);
|
|
||||||
|
|
||||||
virtio_init(vdev, VIRTIO_ID_SOUND, sizeof(virtio_snd_config));
|
|
||||||
virtio_add_feature(&vsnd->features, VIRTIO_F_VERSION_1);
|
|
||||||
|
|
||||||
/* set default params for all streams */
|
/* set default params for all streams */
|
||||||
default_params.features = 0;
|
default_params.features = 0;
|
||||||
@@ -1129,23 +1126,18 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
|
|||||||
status = virtio_snd_set_pcm_params(vsnd, i, &default_params);
|
status = virtio_snd_set_pcm_params(vsnd, i, &default_params);
|
||||||
if (status != cpu_to_le32(VIRTIO_SND_S_OK)) {
|
if (status != cpu_to_le32(VIRTIO_SND_S_OK)) {
|
||||||
error_setg(errp,
|
error_setg(errp,
|
||||||
"Can't initialize stream params, device responded with %s.",
|
"Can't initalize stream params, device responded with %s.",
|
||||||
print_code(status));
|
print_code(status));
|
||||||
goto error_cleanup;
|
return;
|
||||||
}
|
}
|
||||||
status = virtio_snd_pcm_prepare(vsnd, i);
|
status = virtio_snd_pcm_prepare(vsnd, i);
|
||||||
if (status != cpu_to_le32(VIRTIO_SND_S_OK)) {
|
if (status != cpu_to_le32(VIRTIO_SND_S_OK)) {
|
||||||
error_setg(errp,
|
error_setg(errp,
|
||||||
"Can't prepare streams, device responded with %s.",
|
"Can't prepare streams, device responded with %s.",
|
||||||
print_code(status));
|
print_code(status));
|
||||||
goto error_cleanup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
error_cleanup:
|
}
|
||||||
virtio_snd_unrealize(dev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void return_tx_buffer(VirtIOSoundPCMStream *stream,
|
static inline void return_tx_buffer(VirtIOSoundPCMStream *stream,
|
||||||
|
|||||||
@@ -233,10 +233,6 @@ static void atmega_realize(DeviceState *dev, Error **errp)
|
|||||||
|
|
||||||
/* CPU */
|
/* CPU */
|
||||||
object_initialize_child(OBJECT(dev), "cpu", &s->cpu, mc->cpu_type);
|
object_initialize_child(OBJECT(dev), "cpu", &s->cpu, mc->cpu_type);
|
||||||
|
|
||||||
object_property_set_uint(OBJECT(&s->cpu), "init-sp",
|
|
||||||
mc->io_size + mc->sram_size - 1, &error_abort);
|
|
||||||
|
|
||||||
qdev_realize(DEVICE(&s->cpu), NULL, &error_abort);
|
qdev_realize(DEVICE(&s->cpu), NULL, &error_abort);
|
||||||
cpudev = DEVICE(&s->cpu);
|
cpudev = DEVICE(&s->cpu);
|
||||||
|
|
||||||
|
|||||||
@@ -80,39 +80,16 @@ struct PFlashCFI01 {
|
|||||||
uint16_t ident3;
|
uint16_t ident3;
|
||||||
uint8_t cfi_table[0x52];
|
uint8_t cfi_table[0x52];
|
||||||
uint64_t counter;
|
uint64_t counter;
|
||||||
uint32_t writeblock_size;
|
unsigned int writeblock_size;
|
||||||
MemoryRegion mem;
|
MemoryRegion mem;
|
||||||
char *name;
|
char *name;
|
||||||
void *storage;
|
void *storage;
|
||||||
VMChangeStateEntry *vmstate;
|
VMChangeStateEntry *vmstate;
|
||||||
bool old_multiple_chip_handling;
|
bool old_multiple_chip_handling;
|
||||||
|
|
||||||
/* block update buffer */
|
|
||||||
unsigned char *blk_bytes;
|
|
||||||
uint32_t blk_offset;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int pflash_post_load(void *opaque, int version_id);
|
static int pflash_post_load(void *opaque, int version_id);
|
||||||
|
|
||||||
static bool pflash_blk_write_state_needed(void *opaque)
|
|
||||||
{
|
|
||||||
PFlashCFI01 *pfl = opaque;
|
|
||||||
|
|
||||||
return (pfl->blk_offset != -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const VMStateDescription vmstate_pflash_blk_write = {
|
|
||||||
.name = "pflash_cfi01_blk_write",
|
|
||||||
.version_id = 1,
|
|
||||||
.minimum_version_id = 1,
|
|
||||||
.needed = pflash_blk_write_state_needed,
|
|
||||||
.fields = (const VMStateField[]) {
|
|
||||||
VMSTATE_VBUFFER_UINT32(blk_bytes, PFlashCFI01, 0, NULL, writeblock_size),
|
|
||||||
VMSTATE_UINT32(blk_offset, PFlashCFI01),
|
|
||||||
VMSTATE_END_OF_LIST()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const VMStateDescription vmstate_pflash = {
|
static const VMStateDescription vmstate_pflash = {
|
||||||
.name = "pflash_cfi01",
|
.name = "pflash_cfi01",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
@@ -124,10 +101,6 @@ static const VMStateDescription vmstate_pflash = {
|
|||||||
VMSTATE_UINT8(status, PFlashCFI01),
|
VMSTATE_UINT8(status, PFlashCFI01),
|
||||||
VMSTATE_UINT64(counter, PFlashCFI01),
|
VMSTATE_UINT64(counter, PFlashCFI01),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
},
|
|
||||||
.subsections = (const VMStateDescription * []) {
|
|
||||||
&vmstate_pflash_blk_write,
|
|
||||||
NULL
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -252,10 +225,34 @@ static uint32_t pflash_data_read(PFlashCFI01 *pfl, hwaddr offset,
|
|||||||
uint32_t ret;
|
uint32_t ret;
|
||||||
|
|
||||||
p = pfl->storage;
|
p = pfl->storage;
|
||||||
|
switch (width) {
|
||||||
|
case 1:
|
||||||
|
ret = p[offset];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
if (be) {
|
if (be) {
|
||||||
ret = ldn_be_p(p + offset, width);
|
ret = p[offset] << 8;
|
||||||
|
ret |= p[offset + 1];
|
||||||
} else {
|
} else {
|
||||||
ret = ldn_le_p(p + offset, width);
|
ret = p[offset];
|
||||||
|
ret |= p[offset + 1] << 8;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
if (be) {
|
||||||
|
ret = p[offset] << 24;
|
||||||
|
ret |= p[offset + 1] << 16;
|
||||||
|
ret |= p[offset + 2] << 8;
|
||||||
|
ret |= p[offset + 3];
|
||||||
|
} else {
|
||||||
|
ret = p[offset];
|
||||||
|
ret |= p[offset + 1] << 8;
|
||||||
|
ret |= p[offset + 2] << 16;
|
||||||
|
ret |= p[offset + 3] << 24;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
}
|
}
|
||||||
trace_pflash_data_read(pfl->name, offset, width, ret);
|
trace_pflash_data_read(pfl->name, offset, width, ret);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -403,61 +400,40 @@ static void pflash_update(PFlashCFI01 *pfl, int offset,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copy current flash content to block update buffer */
|
|
||||||
static void pflash_blk_write_start(PFlashCFI01 *pfl, hwaddr offset)
|
|
||||||
{
|
|
||||||
hwaddr mask = ~(pfl->writeblock_size - 1);
|
|
||||||
|
|
||||||
trace_pflash_write_block_start(pfl->name, pfl->counter);
|
|
||||||
pfl->blk_offset = offset & mask;
|
|
||||||
memcpy(pfl->blk_bytes, pfl->storage + pfl->blk_offset,
|
|
||||||
pfl->writeblock_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* commit block update buffer changes */
|
|
||||||
static void pflash_blk_write_flush(PFlashCFI01 *pfl)
|
|
||||||
{
|
|
||||||
g_assert(pfl->blk_offset != -1);
|
|
||||||
trace_pflash_write_block_flush(pfl->name);
|
|
||||||
memcpy(pfl->storage + pfl->blk_offset, pfl->blk_bytes,
|
|
||||||
pfl->writeblock_size);
|
|
||||||
pflash_update(pfl, pfl->blk_offset, pfl->writeblock_size);
|
|
||||||
pfl->blk_offset = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* discard block update buffer changes */
|
|
||||||
static void pflash_blk_write_abort(PFlashCFI01 *pfl)
|
|
||||||
{
|
|
||||||
trace_pflash_write_block_abort(pfl->name);
|
|
||||||
pfl->blk_offset = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void pflash_data_write(PFlashCFI01 *pfl, hwaddr offset,
|
static inline void pflash_data_write(PFlashCFI01 *pfl, hwaddr offset,
|
||||||
uint32_t value, int width, int be)
|
uint32_t value, int width, int be)
|
||||||
{
|
{
|
||||||
uint8_t *p;
|
uint8_t *p = pfl->storage;
|
||||||
|
|
||||||
if (pfl->blk_offset != -1) {
|
|
||||||
/* block write: redirect writes to block update buffer */
|
|
||||||
if ((offset < pfl->blk_offset) ||
|
|
||||||
(offset + width > pfl->blk_offset + pfl->writeblock_size)) {
|
|
||||||
pfl->status |= 0x10; /* Programming error */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
trace_pflash_data_write_block(pfl->name, offset, width, value,
|
|
||||||
pfl->counter);
|
|
||||||
p = pfl->blk_bytes + (offset - pfl->blk_offset);
|
|
||||||
} else {
|
|
||||||
/* write directly to storage */
|
|
||||||
trace_pflash_data_write(pfl->name, offset, width, value);
|
|
||||||
p = pfl->storage + offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
trace_pflash_data_write(pfl->name, offset, width, value, pfl->counter);
|
||||||
|
switch (width) {
|
||||||
|
case 1:
|
||||||
|
p[offset] = value;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
if (be) {
|
if (be) {
|
||||||
stn_be_p(p, width, value);
|
p[offset] = value >> 8;
|
||||||
|
p[offset + 1] = value;
|
||||||
} else {
|
} else {
|
||||||
stn_le_p(p, width, value);
|
p[offset] = value;
|
||||||
|
p[offset + 1] = value >> 8;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
if (be) {
|
||||||
|
p[offset] = value >> 24;
|
||||||
|
p[offset + 1] = value >> 16;
|
||||||
|
p[offset + 2] = value >> 8;
|
||||||
|
p[offset + 3] = value;
|
||||||
|
} else {
|
||||||
|
p[offset] = value;
|
||||||
|
p[offset + 1] = value >> 8;
|
||||||
|
p[offset + 2] = value >> 16;
|
||||||
|
p[offset + 3] = value >> 24;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pflash_write(PFlashCFI01 *pfl, hwaddr offset,
|
static void pflash_write(PFlashCFI01 *pfl, hwaddr offset,
|
||||||
@@ -572,9 +548,9 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset,
|
|||||||
} else {
|
} else {
|
||||||
value = extract32(value, 0, pfl->bank_width * 8);
|
value = extract32(value, 0, pfl->bank_width * 8);
|
||||||
}
|
}
|
||||||
|
trace_pflash_write_block(pfl->name, value);
|
||||||
pfl->counter = value;
|
pfl->counter = value;
|
||||||
pfl->wcycle++;
|
pfl->wcycle++;
|
||||||
pflash_blk_write_start(pfl, offset);
|
|
||||||
break;
|
break;
|
||||||
case 0x60:
|
case 0x60:
|
||||||
if (cmd == 0xd0) {
|
if (cmd == 0xd0) {
|
||||||
@@ -605,7 +581,12 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset,
|
|||||||
switch (pfl->cmd) {
|
switch (pfl->cmd) {
|
||||||
case 0xe8: /* Block write */
|
case 0xe8: /* Block write */
|
||||||
/* FIXME check @offset, @width */
|
/* FIXME check @offset, @width */
|
||||||
if (!pfl->ro && (pfl->blk_offset != -1)) {
|
if (!pfl->ro) {
|
||||||
|
/*
|
||||||
|
* FIXME writing straight to memory is *wrong*. We
|
||||||
|
* should write to a buffer, and flush it to memory
|
||||||
|
* only on confirm command (see below).
|
||||||
|
*/
|
||||||
pflash_data_write(pfl, offset, value, width, be);
|
pflash_data_write(pfl, offset, value, width, be);
|
||||||
} else {
|
} else {
|
||||||
pfl->status |= 0x10; /* Programming error */
|
pfl->status |= 0x10; /* Programming error */
|
||||||
@@ -614,8 +595,18 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset,
|
|||||||
pfl->status |= 0x80;
|
pfl->status |= 0x80;
|
||||||
|
|
||||||
if (!pfl->counter) {
|
if (!pfl->counter) {
|
||||||
|
hwaddr mask = pfl->writeblock_size - 1;
|
||||||
|
mask = ~mask;
|
||||||
|
|
||||||
trace_pflash_write(pfl->name, "block write finished");
|
trace_pflash_write(pfl->name, "block write finished");
|
||||||
pfl->wcycle++;
|
pfl->wcycle++;
|
||||||
|
if (!pfl->ro) {
|
||||||
|
/* Flush the entire write buffer onto backing storage. */
|
||||||
|
/* FIXME premature! */
|
||||||
|
pflash_update(pfl, offset & mask, pfl->writeblock_size);
|
||||||
|
} else {
|
||||||
|
pfl->status |= 0x10; /* Programming error */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pfl->counter--;
|
pfl->counter--;
|
||||||
@@ -627,17 +618,20 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset,
|
|||||||
case 3: /* Confirm mode */
|
case 3: /* Confirm mode */
|
||||||
switch (pfl->cmd) {
|
switch (pfl->cmd) {
|
||||||
case 0xe8: /* Block write */
|
case 0xe8: /* Block write */
|
||||||
if ((cmd == 0xd0) && !(pfl->status & 0x10)) {
|
if (cmd == 0xd0) {
|
||||||
pflash_blk_write_flush(pfl);
|
/* FIXME this is where we should write out the buffer */
|
||||||
pfl->wcycle = 0;
|
pfl->wcycle = 0;
|
||||||
pfl->status |= 0x80;
|
pfl->status |= 0x80;
|
||||||
} else {
|
} else {
|
||||||
pflash_blk_write_abort(pfl);
|
qemu_log_mask(LOG_UNIMP,
|
||||||
|
"%s: Aborting write to buffer not implemented,"
|
||||||
|
" the data is already written to storage!\n"
|
||||||
|
"Flash device reset into READ mode.\n",
|
||||||
|
__func__);
|
||||||
goto mode_read_array;
|
goto mode_read_array;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
pflash_blk_write_abort(pfl);
|
|
||||||
goto error_flash;
|
goto error_flash;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -871,9 +865,6 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
|
|||||||
pfl->cmd = 0x00;
|
pfl->cmd = 0x00;
|
||||||
pfl->status = 0x80; /* WSM ready */
|
pfl->status = 0x80; /* WSM ready */
|
||||||
pflash_cfi01_fill_cfi_table(pfl);
|
pflash_cfi01_fill_cfi_table(pfl);
|
||||||
|
|
||||||
pfl->blk_bytes = g_malloc(pfl->writeblock_size);
|
|
||||||
pfl->blk_offset = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pflash_cfi01_system_reset(DeviceState *dev)
|
static void pflash_cfi01_system_reset(DeviceState *dev)
|
||||||
@@ -893,8 +884,6 @@ static void pflash_cfi01_system_reset(DeviceState *dev)
|
|||||||
* This model deliberately ignores this delay.
|
* This model deliberately ignores this delay.
|
||||||
*/
|
*/
|
||||||
pfl->status = 0x80;
|
pfl->status = 0x80;
|
||||||
|
|
||||||
pfl->blk_offset = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Property pflash_cfi01_properties[] = {
|
static Property pflash_cfi01_properties[] = {
|
||||||
|
|||||||
@@ -546,7 +546,7 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
|
|||||||
}
|
}
|
||||||
goto reset_flash;
|
goto reset_flash;
|
||||||
}
|
}
|
||||||
trace_pflash_data_write(pfl->name, offset, width, value);
|
trace_pflash_data_write(pfl->name, offset, width, value, 0);
|
||||||
if (!pfl->ro) {
|
if (!pfl->ro) {
|
||||||
p = (uint8_t *)pfl->storage + offset;
|
p = (uint8_t *)pfl->storage + offset;
|
||||||
if (pfl->be) {
|
if (pfl->be) {
|
||||||
|
|||||||
@@ -12,8 +12,7 @@ fdctrl_tc_pulse(int level) "TC pulse: %u"
|
|||||||
pflash_chip_erase_invalid(const char *name, uint64_t offset) "%s: chip erase: invalid address 0x%" PRIx64
|
pflash_chip_erase_invalid(const char *name, uint64_t offset) "%s: chip erase: invalid address 0x%" PRIx64
|
||||||
pflash_chip_erase_start(const char *name) "%s: start chip erase"
|
pflash_chip_erase_start(const char *name) "%s: start chip erase"
|
||||||
pflash_data_read(const char *name, uint64_t offset, unsigned size, uint32_t value) "%s: data offset:0x%04"PRIx64" size:%u value:0x%04x"
|
pflash_data_read(const char *name, uint64_t offset, unsigned size, uint32_t value) "%s: data offset:0x%04"PRIx64" size:%u value:0x%04x"
|
||||||
pflash_data_write(const char *name, uint64_t offset, unsigned size, uint32_t value) "%s: data offset:0x%04"PRIx64" size:%u value:0x%04x"
|
pflash_data_write(const char *name, uint64_t offset, unsigned size, uint32_t value, uint64_t counter) "%s: data offset:0x%04"PRIx64" size:%u value:0x%04x counter:0x%016"PRIx64
|
||||||
pflash_data_write_block(const char *name, uint64_t offset, unsigned size, uint32_t value, uint64_t counter) "%s: data offset:0x%04"PRIx64" size:%u value:0x%04x counter:0x%016"PRIx64
|
|
||||||
pflash_device_id(const char *name, uint16_t id) "%s: read device ID: 0x%04x"
|
pflash_device_id(const char *name, uint16_t id) "%s: read device ID: 0x%04x"
|
||||||
pflash_device_info(const char *name, uint64_t offset) "%s: read device information offset:0x%04" PRIx64
|
pflash_device_info(const char *name, uint64_t offset) "%s: read device information offset:0x%04" PRIx64
|
||||||
pflash_erase_complete(const char *name) "%s: sector erase complete"
|
pflash_erase_complete(const char *name) "%s: sector erase complete"
|
||||||
@@ -33,9 +32,7 @@ pflash_unlock0_failed(const char *name, uint64_t offset, uint8_t cmd, uint16_t a
|
|||||||
pflash_unlock1_failed(const char *name, uint64_t offset, uint8_t cmd) "%s: unlock0 failed 0x%" PRIx64 " 0x%02x"
|
pflash_unlock1_failed(const char *name, uint64_t offset, uint8_t cmd) "%s: unlock0 failed 0x%" PRIx64 " 0x%02x"
|
||||||
pflash_unsupported_device_configuration(const char *name, uint8_t width, uint8_t max) "%s: unsupported device configuration: device_width:%d max_device_width:%d"
|
pflash_unsupported_device_configuration(const char *name, uint8_t width, uint8_t max) "%s: unsupported device configuration: device_width:%d max_device_width:%d"
|
||||||
pflash_write(const char *name, const char *str) "%s: %s"
|
pflash_write(const char *name, const char *str) "%s: %s"
|
||||||
pflash_write_block_start(const char *name, uint32_t value) "%s: block write start: bytes:0x%x"
|
pflash_write_block(const char *name, uint32_t value) "%s: block write: bytes:0x%x"
|
||||||
pflash_write_block_flush(const char *name) "%s: block write flush"
|
|
||||||
pflash_write_block_abort(const char *name) "%s: block write abort"
|
|
||||||
pflash_write_block_erase(const char *name, uint64_t offset, uint64_t len) "%s: block erase offset:0x%" PRIx64 " bytes:0x%" PRIx64
|
pflash_write_block_erase(const char *name, uint64_t offset, uint64_t len) "%s: block erase offset:0x%" PRIx64 " bytes:0x%" PRIx64
|
||||||
pflash_write_failed(const char *name, uint64_t offset, uint8_t cmd) "%s: command failed 0x%" PRIx64 " 0x%02x"
|
pflash_write_failed(const char *name, uint64_t offset, uint8_t cmd) "%s: command failed 0x%" PRIx64 " 0x%02x"
|
||||||
pflash_write_invalid(const char *name, uint8_t cmd) "%s: invalid write for command 0x%02x"
|
pflash_write_invalid(const char *name, uint8_t cmd) "%s: invalid write for command 0x%02x"
|
||||||
|
|||||||
@@ -326,6 +326,7 @@ static int vhost_user_blk_connect(DeviceState *dev, Error **errp)
|
|||||||
if (s->connected) {
|
if (s->connected) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
s->connected = true;
|
||||||
|
|
||||||
s->dev.num_queues = s->num_queues;
|
s->dev.num_queues = s->num_queues;
|
||||||
s->dev.nvqs = s->num_queues;
|
s->dev.nvqs = s->num_queues;
|
||||||
@@ -342,14 +343,15 @@ static int vhost_user_blk_connect(DeviceState *dev, Error **errp)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->connected = true;
|
|
||||||
|
|
||||||
/* restore vhost state */
|
/* restore vhost state */
|
||||||
if (virtio_device_started(vdev, vdev->status)) {
|
if (virtio_device_started(vdev, vdev->status)) {
|
||||||
ret = vhost_user_blk_start(vdev, errp);
|
ret = vhost_user_blk_start(vdev, errp);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vhost_user_blk_disconnect(DeviceState *dev)
|
static void vhost_user_blk_disconnect(DeviceState *dev)
|
||||||
|
|||||||
@@ -91,28 +91,10 @@ static bool xen_block_find_free_vdev(XenBlockDevice *blockdev, Error **errp)
|
|||||||
|
|
||||||
existing_frontends = qemu_xen_xs_directory(xenbus->xsh, XBT_NULL, fe_path,
|
existing_frontends = qemu_xen_xs_directory(xenbus->xsh, XBT_NULL, fe_path,
|
||||||
&nr_existing);
|
&nr_existing);
|
||||||
if (!existing_frontends) {
|
if (!existing_frontends && errno != ENOENT) {
|
||||||
if (errno == ENOENT) {
|
|
||||||
/*
|
|
||||||
* If the frontend directory doesn't exist because there are
|
|
||||||
* no existing vbd devices, that's fine. Just ensure that we
|
|
||||||
* don't dereference the NULL existing_frontends pointer, by
|
|
||||||
* checking that nr_existing is zero so the loop below is not
|
|
||||||
* entered.
|
|
||||||
*
|
|
||||||
* In fact this is redundant since nr_existing is initialized
|
|
||||||
* to zero, but setting it again here makes it abundantly clear
|
|
||||||
* to Coverity, and to the human reader who doesn't know the
|
|
||||||
* semantics of qemu_xen_xs_directory() off the top of their
|
|
||||||
* head.
|
|
||||||
*/
|
|
||||||
nr_existing = 0;
|
|
||||||
} else {
|
|
||||||
/* All other errors accessing the frontend directory are fatal. */
|
|
||||||
error_setg_errno(errp, errno, "cannot read %s", fe_path);
|
error_setg_errno(errp, errno, "cannot read %s", fe_path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
memset(used_devs, 0, sizeof(used_devs));
|
memset(used_devs, 0, sizeof(used_devs));
|
||||||
for (i = 0; i < nr_existing; i++) {
|
for (i = 0; i < nr_existing; i++) {
|
||||||
|
|||||||
@@ -505,7 +505,7 @@ ssize_t load_elf_ram_sym(const char *filename,
|
|||||||
clear_lsb, data_swab, as, load_rom, sym_cb);
|
clear_lsb, data_swab, as, load_rom, sym_cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret > 0) {
|
if (ret != ELF_LOAD_FAILED) {
|
||||||
debuginfo_report_elf(filename, fd, 0);
|
debuginfo_report_elf(filename, fd, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1189,6 +1189,11 @@ bool machine_mem_merge(MachineState *machine)
|
|||||||
return machine->mem_merge;
|
return machine->mem_merge;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool machine_require_guest_memfd(MachineState *machine)
|
||||||
|
{
|
||||||
|
return machine->require_guest_memfd;
|
||||||
|
}
|
||||||
|
|
||||||
static char *cpu_slot_to_string(const CPUArchId *cpu)
|
static char *cpu_slot_to_string(const CPUArchId *cpu)
|
||||||
{
|
{
|
||||||
GString *s = g_string_new(NULL);
|
GString *s = g_string_new(NULL);
|
||||||
|
|||||||
@@ -689,36 +689,23 @@ static void get_prop_array(Object *obj, Visitor *v, const char *name,
|
|||||||
Property *prop = opaque;
|
Property *prop = opaque;
|
||||||
uint32_t *alenptr = object_field_prop_ptr(obj, prop);
|
uint32_t *alenptr = object_field_prop_ptr(obj, prop);
|
||||||
void **arrayptr = (void *)obj + prop->arrayoffset;
|
void **arrayptr = (void *)obj + prop->arrayoffset;
|
||||||
char *elemptr = *arrayptr;
|
char *elem = *arrayptr;
|
||||||
ArrayElementList *list = NULL, *elem;
|
GenericList *list;
|
||||||
ArrayElementList **tail = &list;
|
const size_t list_elem_size = sizeof(*list) + prop->arrayfieldsize;
|
||||||
const size_t size = sizeof(*list);
|
|
||||||
int i;
|
int i;
|
||||||
bool ok;
|
bool ok;
|
||||||
|
|
||||||
/* At least the string output visitor needs a real list */
|
if (!visit_start_list(v, name, &list, list_elem_size, errp)) {
|
||||||
for (i = 0; i < *alenptr; i++) {
|
|
||||||
elem = g_new0(ArrayElementList, 1);
|
|
||||||
elem->value = elemptr;
|
|
||||||
elemptr += prop->arrayfieldsize;
|
|
||||||
|
|
||||||
*tail = elem;
|
|
||||||
tail = &elem->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!visit_start_list(v, name, (GenericList **) &list, size, errp)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
elem = list;
|
for (i = 0; i < *alenptr; i++) {
|
||||||
while (elem) {
|
Property elem_prop = array_elem_prop(obj, prop, name, elem);
|
||||||
Property elem_prop = array_elem_prop(obj, prop, name, elem->value);
|
|
||||||
prop->arrayinfo->get(obj, v, NULL, &elem_prop, errp);
|
prop->arrayinfo->get(obj, v, NULL, &elem_prop, errp);
|
||||||
if (*errp) {
|
if (*errp) {
|
||||||
goto out_obj;
|
goto out_obj;
|
||||||
}
|
}
|
||||||
elem = (ArrayElementList *) visit_next_list(v, (GenericList*) elem,
|
elem += prop->arrayfieldsize;
|
||||||
size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* visit_check_list() can only fail for input visitors */
|
/* visit_check_list() can only fail for input visitors */
|
||||||
@@ -727,12 +714,6 @@ static void get_prop_array(Object *obj, Visitor *v, const char *name,
|
|||||||
|
|
||||||
out_obj:
|
out_obj:
|
||||||
visit_end_list(v, (void**) &list);
|
visit_end_list(v, (void**) &list);
|
||||||
|
|
||||||
while (list) {
|
|
||||||
elem = list;
|
|
||||||
list = elem->next;
|
|
||||||
g_free(elem);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void default_prop_array(ObjectProperty *op, const Property *prop)
|
static void default_prop_array(ObjectProperty *op, const Property *prop)
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ static uint64_t cxl_cache_mem_read_reg(void *opaque, hwaddr offset,
|
|||||||
return 0;
|
return 0;
|
||||||
default:
|
default:
|
||||||
/*
|
/*
|
||||||
* In line with specification limitaions on access sizes, this
|
* In line with specifiction limitaions on access sizes, this
|
||||||
* routine is not called with other sizes.
|
* routine is not called with other sizes.
|
||||||
*/
|
*/
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
@@ -152,7 +152,7 @@ static void cxl_cache_mem_write_reg(void *opaque, hwaddr offset, uint64_t value,
|
|||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
/*
|
/*
|
||||||
* In line with specification limitaions on access sizes, this
|
* In line with specifiction limitaions on access sizes, this
|
||||||
* routine is not called with other sizes.
|
* routine is not called with other sizes.
|
||||||
*/
|
*/
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
|
|||||||
@@ -431,7 +431,7 @@ static CXLRetCode cmd_identify_switch_device(const struct cxl_cmd *cmd,
|
|||||||
out = (struct cxl_fmapi_ident_switch_dev_resp_pl *)payload_out;
|
out = (struct cxl_fmapi_ident_switch_dev_resp_pl *)payload_out;
|
||||||
*out = (struct cxl_fmapi_ident_switch_dev_resp_pl) {
|
*out = (struct cxl_fmapi_ident_switch_dev_resp_pl) {
|
||||||
.num_physical_ports = num_phys_ports + 1, /* 1 USP */
|
.num_physical_ports = num_phys_ports + 1, /* 1 USP */
|
||||||
.num_vcss = 1, /* Not yet support multiple VCS - potentially tricky */
|
.num_vcss = 1, /* Not yet support multiple VCS - potentialy tricky */
|
||||||
.active_vcs_bitmask[0] = 0x1,
|
.active_vcs_bitmask[0] = 0x1,
|
||||||
.total_vppbs = num_phys_ports + 1,
|
.total_vppbs = num_phys_ports + 1,
|
||||||
.bound_vppbs = num_phys_ports + 1,
|
.bound_vppbs = num_phys_ports + 1,
|
||||||
|
|||||||
@@ -33,13 +33,13 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Ref: UG1087 (v1.7) February 8, 2019
|
* Ref: UG1087 (v1.7) February 8, 2019
|
||||||
* https://www.xilinx.com/html_docs/registers/ug1087/ug1087-zynq-ultrascale-registers
|
* https://www.xilinx.com/html_docs/registers/ug1087/ug1087-zynq-ultrascale-registers.html
|
||||||
* CSUDMA Module section
|
* CSUDMA Module section
|
||||||
*/
|
*/
|
||||||
REG32(ADDR, 0x0)
|
REG32(ADDR, 0x0)
|
||||||
FIELD(ADDR, ADDR, 2, 30) /* wo */
|
FIELD(ADDR, ADDR, 2, 30) /* wo */
|
||||||
REG32(SIZE, 0x4)
|
REG32(SIZE, 0x4)
|
||||||
FIELD(SIZE, SIZE, 2, 27)
|
FIELD(SIZE, SIZE, 2, 27) /* wo */
|
||||||
FIELD(SIZE, LAST_WORD, 0, 1) /* rw, only exists in SRC */
|
FIELD(SIZE, LAST_WORD, 0, 1) /* rw, only exists in SRC */
|
||||||
REG32(STATUS, 0x8)
|
REG32(STATUS, 0x8)
|
||||||
FIELD(STATUS, DONE_CNT, 13, 3) /* wtc */
|
FIELD(STATUS, DONE_CNT, 13, 3) /* wtc */
|
||||||
@@ -335,14 +335,10 @@ static uint64_t addr_pre_write(RegisterInfo *reg, uint64_t val)
|
|||||||
static uint64_t size_pre_write(RegisterInfo *reg, uint64_t val)
|
static uint64_t size_pre_write(RegisterInfo *reg, uint64_t val)
|
||||||
{
|
{
|
||||||
XlnxCSUDMA *s = XLNX_CSU_DMA(reg->opaque);
|
XlnxCSUDMA *s = XLNX_CSU_DMA(reg->opaque);
|
||||||
uint64_t size = val & R_SIZE_SIZE_MASK;
|
|
||||||
|
|
||||||
if (s->regs[R_SIZE] != 0) {
|
if (s->regs[R_SIZE] != 0) {
|
||||||
if (size || s->is_dst) {
|
|
||||||
qemu_log_mask(LOG_GUEST_ERROR,
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
"%s: Starting DMA while already running.\n",
|
"%s: Starting DMA while already running.\n", __func__);
|
||||||
__func__);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!s->is_dst) {
|
if (!s->is_dst) {
|
||||||
@@ -350,7 +346,7 @@ static uint64_t size_pre_write(RegisterInfo *reg, uint64_t val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Size is word aligned */
|
/* Size is word aligned */
|
||||||
return size;
|
return val & R_SIZE_SIZE_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t size_post_read(RegisterInfo *reg, uint64_t val)
|
static uint64_t size_post_read(RegisterInfo *reg, uint64_t val)
|
||||||
|
|||||||
@@ -36,8 +36,8 @@
|
|||||||
|
|
||||||
#define MIN_SEABIOS_HPPA_VERSION 12 /* require at least this fw version */
|
#define MIN_SEABIOS_HPPA_VERSION 12 /* require at least this fw version */
|
||||||
|
|
||||||
#define HPA_POWER_BUTTON (FIRMWARE_END - 0x10)
|
/* Power button address at &PAGE0->pad[4] */
|
||||||
static hwaddr soft_power_reg;
|
#define HPA_POWER_BUTTON (0x40 + 4 * sizeof(uint32_t))
|
||||||
|
|
||||||
#define enable_lasi_lan() 0
|
#define enable_lasi_lan() 0
|
||||||
|
|
||||||
@@ -45,6 +45,7 @@ static DeviceState *lasi_dev;
|
|||||||
|
|
||||||
static void hppa_powerdown_req(Notifier *n, void *opaque)
|
static void hppa_powerdown_req(Notifier *n, void *opaque)
|
||||||
{
|
{
|
||||||
|
hwaddr soft_power_reg = HPA_POWER_BUTTON;
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
|
|
||||||
val = ldl_be_phys(&address_space_memory, soft_power_reg);
|
val = ldl_be_phys(&address_space_memory, soft_power_reg);
|
||||||
@@ -220,7 +221,7 @@ static FWCfgState *create_fw_cfg(MachineState *ms, PCIBus *pci_bus,
|
|||||||
fw_cfg_add_file(fw_cfg, "/etc/hppa/machine",
|
fw_cfg_add_file(fw_cfg, "/etc/hppa/machine",
|
||||||
g_memdup(mc->name, len), len);
|
g_memdup(mc->name, len), len);
|
||||||
|
|
||||||
val = cpu_to_le64(soft_power_reg);
|
val = cpu_to_le64(HPA_POWER_BUTTON);
|
||||||
fw_cfg_add_file(fw_cfg, "/etc/hppa/power-button-addr",
|
fw_cfg_add_file(fw_cfg, "/etc/hppa/power-button-addr",
|
||||||
g_memdup(&val, sizeof(val)), sizeof(val));
|
g_memdup(&val, sizeof(val)), sizeof(val));
|
||||||
|
|
||||||
@@ -275,7 +276,6 @@ static TranslateFn *machine_HP_common_init_cpus(MachineState *machine)
|
|||||||
unsigned int smp_cpus = machine->smp.cpus;
|
unsigned int smp_cpus = machine->smp.cpus;
|
||||||
TranslateFn *translate;
|
TranslateFn *translate;
|
||||||
MemoryRegion *cpu_region;
|
MemoryRegion *cpu_region;
|
||||||
uint64_t ram_max;
|
|
||||||
|
|
||||||
/* Create CPUs. */
|
/* Create CPUs. */
|
||||||
for (unsigned int i = 0; i < smp_cpus; i++) {
|
for (unsigned int i = 0; i < smp_cpus; i++) {
|
||||||
@@ -288,14 +288,10 @@ static TranslateFn *machine_HP_common_init_cpus(MachineState *machine)
|
|||||||
*/
|
*/
|
||||||
if (hppa_is_pa20(&cpu[0]->env)) {
|
if (hppa_is_pa20(&cpu[0]->env)) {
|
||||||
translate = translate_pa20;
|
translate = translate_pa20;
|
||||||
ram_max = 0xf0000000; /* 3.75 GB (limited by 32-bit firmware) */
|
|
||||||
} else {
|
} else {
|
||||||
translate = translate_pa10;
|
translate = translate_pa10;
|
||||||
ram_max = 0xf0000000; /* 3.75 GB (32-bit CPU) */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
soft_power_reg = translate(NULL, HPA_POWER_BUTTON);
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < smp_cpus; i++) {
|
for (unsigned int i = 0; i < smp_cpus; i++) {
|
||||||
g_autofree char *name = g_strdup_printf("cpu%u-io-eir", i);
|
g_autofree char *name = g_strdup_printf("cpu%u-io-eir", i);
|
||||||
|
|
||||||
@@ -315,9 +311,9 @@ static TranslateFn *machine_HP_common_init_cpus(MachineState *machine)
|
|||||||
cpu_region);
|
cpu_region);
|
||||||
|
|
||||||
/* Main memory region. */
|
/* Main memory region. */
|
||||||
if (machine->ram_size > ram_max) {
|
if (machine->ram_size > 3 * GiB) {
|
||||||
info_report("Max RAM size limited to %" PRIu64 " MB", ram_max / MiB);
|
error_report("RAM size is currently restricted to 3GB");
|
||||||
machine->ram_size = ram_max;
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
memory_region_add_subregion_overlap(addr_space, 0, machine->ram, -1);
|
memory_region_add_subregion_overlap(addr_space, 0, machine->ram, -1);
|
||||||
|
|
||||||
@@ -347,10 +343,8 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus,
|
|||||||
SysBusDevice *s;
|
SysBusDevice *s;
|
||||||
|
|
||||||
/* SCSI disk setup. */
|
/* SCSI disk setup. */
|
||||||
if (drive_get_max_bus(IF_SCSI) >= 0) {
|
|
||||||
dev = DEVICE(pci_create_simple(pci_bus, -1, "lsi53c895a"));
|
dev = DEVICE(pci_create_simple(pci_bus, -1, "lsi53c895a"));
|
||||||
lsi53c8xx_handle_legacy_cmdline(dev);
|
lsi53c8xx_handle_legacy_cmdline(dev);
|
||||||
}
|
|
||||||
|
|
||||||
/* Graphics setup. */
|
/* Graphics setup. */
|
||||||
if (machine->enable_graphics && vga_interface_type != VGA_NONE) {
|
if (machine->enable_graphics && vga_interface_type != VGA_NONE) {
|
||||||
@@ -363,7 +357,7 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Network setup. */
|
/* Network setup. */
|
||||||
if (nd_table[0].used && enable_lasi_lan()) {
|
if (enable_lasi_lan()) {
|
||||||
lasi_82596_init(addr_space, translate(NULL, LASI_LAN_HPA),
|
lasi_82596_init(addr_space, translate(NULL, LASI_LAN_HPA),
|
||||||
qdev_get_gpio_in(lasi_dev, LASI_IRQ_LAN_HPA));
|
qdev_get_gpio_in(lasi_dev, LASI_IRQ_LAN_HPA));
|
||||||
}
|
}
|
||||||
@@ -388,7 +382,7 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus,
|
|||||||
pci_set_word(&pci_dev->config[PCI_SUBSYSTEM_ID], 0x1227); /* Powerbar */
|
pci_set_word(&pci_dev->config[PCI_SUBSYSTEM_ID], 0x1227); /* Powerbar */
|
||||||
|
|
||||||
/* create a second serial PCI card when running Astro */
|
/* create a second serial PCI card when running Astro */
|
||||||
if (serial_hd(1) && !lasi_dev) {
|
if (!lasi_dev) {
|
||||||
pci_dev = pci_new(-1, "pci-serial-4x");
|
pci_dev = pci_new(-1, "pci-serial-4x");
|
||||||
qdev_prop_set_chr(DEVICE(pci_dev), "chardev1", serial_hd(1));
|
qdev_prop_set_chr(DEVICE(pci_dev), "chardev1", serial_hd(1));
|
||||||
qdev_prop_set_chr(DEVICE(pci_dev), "chardev2", serial_hd(2));
|
qdev_prop_set_chr(DEVICE(pci_dev), "chardev2", serial_hd(2));
|
||||||
@@ -678,18 +672,19 @@ static void hppa_nmi(NMIState *n, int cpu_index, Error **errp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HP_B160L_machine_init_class_init(ObjectClass *oc, void *data)
|
static const char *HP_B160L_machine_valid_cpu_types[] = {
|
||||||
{
|
|
||||||
static const char * const valid_cpu_types[] = {
|
|
||||||
TYPE_HPPA_CPU,
|
TYPE_HPPA_CPU,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void HP_B160L_machine_init_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
MachineClass *mc = MACHINE_CLASS(oc);
|
MachineClass *mc = MACHINE_CLASS(oc);
|
||||||
NMIClass *nc = NMI_CLASS(oc);
|
NMIClass *nc = NMI_CLASS(oc);
|
||||||
|
|
||||||
mc->desc = "HP B160L workstation";
|
mc->desc = "HP B160L workstation";
|
||||||
mc->default_cpu_type = TYPE_HPPA_CPU;
|
mc->default_cpu_type = TYPE_HPPA_CPU;
|
||||||
mc->valid_cpu_types = valid_cpu_types;
|
mc->valid_cpu_types = HP_B160L_machine_valid_cpu_types;
|
||||||
mc->init = machine_HP_B160L_init;
|
mc->init = machine_HP_B160L_init;
|
||||||
mc->reset = hppa_machine_reset;
|
mc->reset = hppa_machine_reset;
|
||||||
mc->block_default_type = IF_SCSI;
|
mc->block_default_type = IF_SCSI;
|
||||||
@@ -714,18 +709,19 @@ static const TypeInfo HP_B160L_machine_init_typeinfo = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static void HP_C3700_machine_init_class_init(ObjectClass *oc, void *data)
|
static const char *HP_C3700_machine_valid_cpu_types[] = {
|
||||||
{
|
|
||||||
static const char * const valid_cpu_types[] = {
|
|
||||||
TYPE_HPPA64_CPU,
|
TYPE_HPPA64_CPU,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void HP_C3700_machine_init_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
MachineClass *mc = MACHINE_CLASS(oc);
|
MachineClass *mc = MACHINE_CLASS(oc);
|
||||||
NMIClass *nc = NMI_CLASS(oc);
|
NMIClass *nc = NMI_CLASS(oc);
|
||||||
|
|
||||||
mc->desc = "HP C3700 workstation";
|
mc->desc = "HP C3700 workstation";
|
||||||
mc->default_cpu_type = TYPE_HPPA64_CPU;
|
mc->default_cpu_type = TYPE_HPPA64_CPU;
|
||||||
mc->valid_cpu_types = valid_cpu_types;
|
mc->valid_cpu_types = HP_C3700_machine_valid_cpu_types;
|
||||||
mc->init = machine_HP_C3700_init;
|
mc->init = machine_HP_C3700_init;
|
||||||
mc->reset = hppa_machine_reset;
|
mc->reset = hppa_machine_reset;
|
||||||
mc->block_default_type = IF_SCSI;
|
mc->block_default_type = IF_SCSI;
|
||||||
|
|||||||
@@ -10,6 +10,11 @@ config SGX
|
|||||||
bool
|
bool
|
||||||
depends on KVM
|
depends on KVM
|
||||||
|
|
||||||
|
config TDX
|
||||||
|
bool
|
||||||
|
select X86_FW_OVMF
|
||||||
|
depends on KVM
|
||||||
|
|
||||||
config PC
|
config PC
|
||||||
bool
|
bool
|
||||||
imply APPLESMC
|
imply APPLESMC
|
||||||
@@ -26,6 +31,7 @@ config PC
|
|||||||
imply QXL
|
imply QXL
|
||||||
imply SEV
|
imply SEV
|
||||||
imply SGX
|
imply SGX
|
||||||
|
imply TDX
|
||||||
imply TEST_DEVICES
|
imply TEST_DEVICES
|
||||||
imply TPM_CRB
|
imply TPM_CRB
|
||||||
imply TPM_TIS_ISA
|
imply TPM_TIS_ISA
|
||||||
|
|||||||
@@ -975,7 +975,8 @@ static void build_dbg_aml(Aml *table)
|
|||||||
aml_append(table, scope);
|
aml_append(table, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Aml *build_link_dev(const char *name, uint8_t uid, Aml *reg)
|
static Aml *build_link_dev(const char *name, uint8_t uid, Aml *reg,
|
||||||
|
bool level_trigger_unsupported)
|
||||||
{
|
{
|
||||||
Aml *dev;
|
Aml *dev;
|
||||||
Aml *crs;
|
Aml *crs;
|
||||||
@@ -987,7 +988,10 @@ static Aml *build_link_dev(const char *name, uint8_t uid, Aml *reg)
|
|||||||
aml_append(dev, aml_name_decl("_UID", aml_int(uid)));
|
aml_append(dev, aml_name_decl("_UID", aml_int(uid)));
|
||||||
|
|
||||||
crs = aml_resource_template();
|
crs = aml_resource_template();
|
||||||
aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
|
aml_append(crs, aml_interrupt(AML_CONSUMER,
|
||||||
|
level_trigger_unsupported ?
|
||||||
|
AML_EDGE : AML_LEVEL,
|
||||||
|
AML_ACTIVE_HIGH,
|
||||||
AML_SHARED, irqs, ARRAY_SIZE(irqs)));
|
AML_SHARED, irqs, ARRAY_SIZE(irqs)));
|
||||||
aml_append(dev, aml_name_decl("_PRS", crs));
|
aml_append(dev, aml_name_decl("_PRS", crs));
|
||||||
|
|
||||||
@@ -1011,7 +1015,8 @@ static Aml *build_link_dev(const char *name, uint8_t uid, Aml *reg)
|
|||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Aml *build_gsi_link_dev(const char *name, uint8_t uid, uint8_t gsi)
|
static Aml *build_gsi_link_dev(const char *name, uint8_t uid,
|
||||||
|
uint8_t gsi, bool level_trigger_unsupported)
|
||||||
{
|
{
|
||||||
Aml *dev;
|
Aml *dev;
|
||||||
Aml *crs;
|
Aml *crs;
|
||||||
@@ -1024,7 +1029,10 @@ static Aml *build_gsi_link_dev(const char *name, uint8_t uid, uint8_t gsi)
|
|||||||
|
|
||||||
crs = aml_resource_template();
|
crs = aml_resource_template();
|
||||||
irqs = gsi;
|
irqs = gsi;
|
||||||
aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
|
aml_append(crs, aml_interrupt(AML_CONSUMER,
|
||||||
|
level_trigger_unsupported ?
|
||||||
|
AML_EDGE : AML_LEVEL,
|
||||||
|
AML_ACTIVE_HIGH,
|
||||||
AML_SHARED, &irqs, 1));
|
AML_SHARED, &irqs, 1));
|
||||||
aml_append(dev, aml_name_decl("_PRS", crs));
|
aml_append(dev, aml_name_decl("_PRS", crs));
|
||||||
|
|
||||||
@@ -1043,7 +1051,7 @@ static Aml *build_gsi_link_dev(const char *name, uint8_t uid, uint8_t gsi)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* _CRS method - get current settings */
|
/* _CRS method - get current settings */
|
||||||
static Aml *build_iqcr_method(bool is_piix4)
|
static Aml *build_iqcr_method(bool is_piix4, bool level_trigger_unsupported)
|
||||||
{
|
{
|
||||||
Aml *if_ctx;
|
Aml *if_ctx;
|
||||||
uint32_t irqs;
|
uint32_t irqs;
|
||||||
@@ -1051,7 +1059,9 @@ static Aml *build_iqcr_method(bool is_piix4)
|
|||||||
Aml *crs = aml_resource_template();
|
Aml *crs = aml_resource_template();
|
||||||
|
|
||||||
irqs = 0;
|
irqs = 0;
|
||||||
aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL,
|
aml_append(crs, aml_interrupt(AML_CONSUMER,
|
||||||
|
level_trigger_unsupported ?
|
||||||
|
AML_EDGE : AML_LEVEL,
|
||||||
AML_ACTIVE_HIGH, AML_SHARED, &irqs, 1));
|
AML_ACTIVE_HIGH, AML_SHARED, &irqs, 1));
|
||||||
aml_append(method, aml_name_decl("PRR0", crs));
|
aml_append(method, aml_name_decl("PRR0", crs));
|
||||||
|
|
||||||
@@ -1085,7 +1095,7 @@ static Aml *build_irq_status_method(void)
|
|||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void build_piix4_pci0_int(Aml *table)
|
static void build_piix4_pci0_int(Aml *table, bool level_trigger_unsupported)
|
||||||
{
|
{
|
||||||
Aml *dev;
|
Aml *dev;
|
||||||
Aml *crs;
|
Aml *crs;
|
||||||
@@ -1098,12 +1108,16 @@ static void build_piix4_pci0_int(Aml *table)
|
|||||||
aml_append(sb_scope, pci0_scope);
|
aml_append(sb_scope, pci0_scope);
|
||||||
|
|
||||||
aml_append(sb_scope, build_irq_status_method());
|
aml_append(sb_scope, build_irq_status_method());
|
||||||
aml_append(sb_scope, build_iqcr_method(true));
|
aml_append(sb_scope, build_iqcr_method(true, level_trigger_unsupported));
|
||||||
|
|
||||||
aml_append(sb_scope, build_link_dev("LNKA", 0, aml_name("PRQ0")));
|
aml_append(sb_scope, build_link_dev("LNKA", 0, aml_name("PRQ0"),
|
||||||
aml_append(sb_scope, build_link_dev("LNKB", 1, aml_name("PRQ1")));
|
level_trigger_unsupported));
|
||||||
aml_append(sb_scope, build_link_dev("LNKC", 2, aml_name("PRQ2")));
|
aml_append(sb_scope, build_link_dev("LNKB", 1, aml_name("PRQ1"),
|
||||||
aml_append(sb_scope, build_link_dev("LNKD", 3, aml_name("PRQ3")));
|
level_trigger_unsupported));
|
||||||
|
aml_append(sb_scope, build_link_dev("LNKC", 2, aml_name("PRQ2"),
|
||||||
|
level_trigger_unsupported));
|
||||||
|
aml_append(sb_scope, build_link_dev("LNKD", 3, aml_name("PRQ3"),
|
||||||
|
level_trigger_unsupported));
|
||||||
|
|
||||||
dev = aml_device("LNKS");
|
dev = aml_device("LNKS");
|
||||||
{
|
{
|
||||||
@@ -1112,7 +1126,9 @@ static void build_piix4_pci0_int(Aml *table)
|
|||||||
|
|
||||||
crs = aml_resource_template();
|
crs = aml_resource_template();
|
||||||
irqs = 9;
|
irqs = 9;
|
||||||
aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL,
|
aml_append(crs, aml_interrupt(AML_CONSUMER,
|
||||||
|
level_trigger_unsupported ?
|
||||||
|
AML_EDGE : AML_LEVEL,
|
||||||
AML_ACTIVE_HIGH, AML_SHARED,
|
AML_ACTIVE_HIGH, AML_SHARED,
|
||||||
&irqs, 1));
|
&irqs, 1));
|
||||||
aml_append(dev, aml_name_decl("_PRS", crs));
|
aml_append(dev, aml_name_decl("_PRS", crs));
|
||||||
@@ -1198,7 +1214,7 @@ static Aml *build_q35_routing_table(const char *str)
|
|||||||
return pkg;
|
return pkg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void build_q35_pci0_int(Aml *table)
|
static void build_q35_pci0_int(Aml *table, bool level_trigger_unsupported)
|
||||||
{
|
{
|
||||||
Aml *method;
|
Aml *method;
|
||||||
Aml *sb_scope = aml_scope("_SB");
|
Aml *sb_scope = aml_scope("_SB");
|
||||||
@@ -1237,25 +1253,41 @@ static void build_q35_pci0_int(Aml *table)
|
|||||||
aml_append(sb_scope, pci0_scope);
|
aml_append(sb_scope, pci0_scope);
|
||||||
|
|
||||||
aml_append(sb_scope, build_irq_status_method());
|
aml_append(sb_scope, build_irq_status_method());
|
||||||
aml_append(sb_scope, build_iqcr_method(false));
|
aml_append(sb_scope, build_iqcr_method(false, level_trigger_unsupported));
|
||||||
|
|
||||||
aml_append(sb_scope, build_link_dev("LNKA", 0, aml_name("PRQA")));
|
aml_append(sb_scope, build_link_dev("LNKA", 0, aml_name("PRQA"),
|
||||||
aml_append(sb_scope, build_link_dev("LNKB", 1, aml_name("PRQB")));
|
level_trigger_unsupported));
|
||||||
aml_append(sb_scope, build_link_dev("LNKC", 2, aml_name("PRQC")));
|
aml_append(sb_scope, build_link_dev("LNKB", 1, aml_name("PRQB"),
|
||||||
aml_append(sb_scope, build_link_dev("LNKD", 3, aml_name("PRQD")));
|
level_trigger_unsupported));
|
||||||
aml_append(sb_scope, build_link_dev("LNKE", 4, aml_name("PRQE")));
|
aml_append(sb_scope, build_link_dev("LNKC", 2, aml_name("PRQC"),
|
||||||
aml_append(sb_scope, build_link_dev("LNKF", 5, aml_name("PRQF")));
|
level_trigger_unsupported));
|
||||||
aml_append(sb_scope, build_link_dev("LNKG", 6, aml_name("PRQG")));
|
aml_append(sb_scope, build_link_dev("LNKD", 3, aml_name("PRQD"),
|
||||||
aml_append(sb_scope, build_link_dev("LNKH", 7, aml_name("PRQH")));
|
level_trigger_unsupported));
|
||||||
|
aml_append(sb_scope, build_link_dev("LNKE", 4, aml_name("PRQE"),
|
||||||
|
level_trigger_unsupported));
|
||||||
|
aml_append(sb_scope, build_link_dev("LNKF", 5, aml_name("PRQF"),
|
||||||
|
level_trigger_unsupported));
|
||||||
|
aml_append(sb_scope, build_link_dev("LNKG", 6, aml_name("PRQG"),
|
||||||
|
level_trigger_unsupported));
|
||||||
|
aml_append(sb_scope, build_link_dev("LNKH", 7, aml_name("PRQH"),
|
||||||
|
level_trigger_unsupported));
|
||||||
|
|
||||||
aml_append(sb_scope, build_gsi_link_dev("GSIA", 0x10, 0x10));
|
aml_append(sb_scope, build_gsi_link_dev("GSIA", 0x10, 0x10,
|
||||||
aml_append(sb_scope, build_gsi_link_dev("GSIB", 0x11, 0x11));
|
level_trigger_unsupported));
|
||||||
aml_append(sb_scope, build_gsi_link_dev("GSIC", 0x12, 0x12));
|
aml_append(sb_scope, build_gsi_link_dev("GSIB", 0x11, 0x11,
|
||||||
aml_append(sb_scope, build_gsi_link_dev("GSID", 0x13, 0x13));
|
level_trigger_unsupported));
|
||||||
aml_append(sb_scope, build_gsi_link_dev("GSIE", 0x14, 0x14));
|
aml_append(sb_scope, build_gsi_link_dev("GSIC", 0x12, 0x12,
|
||||||
aml_append(sb_scope, build_gsi_link_dev("GSIF", 0x15, 0x15));
|
level_trigger_unsupported));
|
||||||
aml_append(sb_scope, build_gsi_link_dev("GSIG", 0x16, 0x16));
|
aml_append(sb_scope, build_gsi_link_dev("GSID", 0x13, 0x13,
|
||||||
aml_append(sb_scope, build_gsi_link_dev("GSIH", 0x17, 0x17));
|
level_trigger_unsupported));
|
||||||
|
aml_append(sb_scope, build_gsi_link_dev("GSIE", 0x14, 0x14,
|
||||||
|
level_trigger_unsupported));
|
||||||
|
aml_append(sb_scope, build_gsi_link_dev("GSIF", 0x15, 0x15,
|
||||||
|
level_trigger_unsupported));
|
||||||
|
aml_append(sb_scope, build_gsi_link_dev("GSIG", 0x16, 0x16,
|
||||||
|
level_trigger_unsupported));
|
||||||
|
aml_append(sb_scope, build_gsi_link_dev("GSIH", 0x17, 0x17,
|
||||||
|
level_trigger_unsupported));
|
||||||
|
|
||||||
aml_append(table, sb_scope);
|
aml_append(table, sb_scope);
|
||||||
}
|
}
|
||||||
@@ -1436,6 +1468,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
|||||||
PCMachineState *pcms = PC_MACHINE(machine);
|
PCMachineState *pcms = PC_MACHINE(machine);
|
||||||
PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(machine);
|
PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(machine);
|
||||||
X86MachineState *x86ms = X86_MACHINE(machine);
|
X86MachineState *x86ms = X86_MACHINE(machine);
|
||||||
|
bool level_trigger_unsupported = x86ms->eoi_intercept_unsupported;
|
||||||
AcpiMcfgInfo mcfg;
|
AcpiMcfgInfo mcfg;
|
||||||
bool mcfg_valid = !!acpi_get_mcfg(&mcfg);
|
bool mcfg_valid = !!acpi_get_mcfg(&mcfg);
|
||||||
uint32_t nr_mem = machine->ram_slots;
|
uint32_t nr_mem = machine->ram_slots;
|
||||||
@@ -1468,7 +1501,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
|||||||
if (pm->pcihp_bridge_en || pm->pcihp_root_en) {
|
if (pm->pcihp_bridge_en || pm->pcihp_root_en) {
|
||||||
build_x86_acpi_pci_hotplug(dsdt, pm->pcihp_io_base);
|
build_x86_acpi_pci_hotplug(dsdt, pm->pcihp_io_base);
|
||||||
}
|
}
|
||||||
build_piix4_pci0_int(dsdt);
|
build_piix4_pci0_int(dsdt, level_trigger_unsupported);
|
||||||
} else if (q35) {
|
} else if (q35) {
|
||||||
sb_scope = aml_scope("_SB");
|
sb_scope = aml_scope("_SB");
|
||||||
dev = aml_device("PCI0");
|
dev = aml_device("PCI0");
|
||||||
@@ -1512,7 +1545,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
|||||||
if (pm->pcihp_bridge_en) {
|
if (pm->pcihp_bridge_en) {
|
||||||
build_x86_acpi_pci_hotplug(dsdt, pm->pcihp_io_base);
|
build_x86_acpi_pci_hotplug(dsdt, pm->pcihp_io_base);
|
||||||
}
|
}
|
||||||
build_q35_pci0_int(dsdt);
|
build_q35_pci0_int(dsdt, level_trigger_unsupported);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (misc->has_hpet) {
|
if (misc->has_hpet) {
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ void acpi_build_madt(GArray *table_data, BIOSLinker *linker,
|
|||||||
const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(x86ms));
|
const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(x86ms));
|
||||||
AcpiTable table = { .sig = "APIC", .rev = 3, .oem_id = oem_id,
|
AcpiTable table = { .sig = "APIC", .rev = 3, .oem_id = oem_id,
|
||||||
.oem_table_id = oem_table_id };
|
.oem_table_id = oem_table_id };
|
||||||
|
bool level_trigger_unsupported = x86ms->eoi_intercept_unsupported;
|
||||||
|
|
||||||
acpi_table_begin(&table, table_data);
|
acpi_table_begin(&table, table_data);
|
||||||
/* Local APIC Address */
|
/* Local APIC Address */
|
||||||
@@ -122,6 +123,29 @@ void acpi_build_madt(GArray *table_data, BIOSLinker *linker,
|
|||||||
IO_APIC_SECONDARY_ADDRESS, IO_APIC_SECONDARY_IRQBASE);
|
IO_APIC_SECONDARY_ADDRESS, IO_APIC_SECONDARY_IRQBASE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (level_trigger_unsupported) {
|
||||||
|
/* Force edge trigger */
|
||||||
|
if (x86ms->apic_xrupt_override) {
|
||||||
|
build_xrupt_override(table_data, 0, 2,
|
||||||
|
/* Flags: active high, edge triggered */
|
||||||
|
1 | (1 << 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = x86ms->apic_xrupt_override ? 1 : 0; i < 16; i++) {
|
||||||
|
build_xrupt_override(table_data, i, i,
|
||||||
|
/* Flags: active high, edge triggered */
|
||||||
|
1 | (1 << 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x86ms->ioapic2) {
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
build_xrupt_override(table_data, IO_APIC_SECONDARY_IRQBASE + i,
|
||||||
|
IO_APIC_SECONDARY_IRQBASE + i,
|
||||||
|
/* Flags: active high, edge triggered */
|
||||||
|
1 | (1 << 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (x86ms->apic_xrupt_override) {
|
if (x86ms->apic_xrupt_override) {
|
||||||
build_xrupt_override(table_data, 0, 2,
|
build_xrupt_override(table_data, 0, 2,
|
||||||
0 /* Flags: Conforms to the specifications of the bus */);
|
0 /* Flags: Conforms to the specifications of the bus */);
|
||||||
@@ -134,6 +158,8 @@ void acpi_build_madt(GArray *table_data, BIOSLinker *linker,
|
|||||||
}
|
}
|
||||||
build_xrupt_override(table_data, i, i,
|
build_xrupt_override(table_data, i, i,
|
||||||
0xd /* Flags: Active high, Level Triggered */);
|
0xd /* Flags: Active high, Level Triggered */);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x2apic_mode) {
|
if (x2apic_mode) {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ i386_ss.add(when: 'CONFIG_PC', if_true: files(
|
|||||||
'port92.c'))
|
'port92.c'))
|
||||||
i386_ss.add(when: 'CONFIG_X86_FW_OVMF', if_true: files('pc_sysfw_ovmf.c'),
|
i386_ss.add(when: 'CONFIG_X86_FW_OVMF', if_true: files('pc_sysfw_ovmf.c'),
|
||||||
if_false: files('pc_sysfw_ovmf-stubs.c'))
|
if_false: files('pc_sysfw_ovmf-stubs.c'))
|
||||||
|
i386_ss.add(when: 'CONFIG_TDX', if_true: files('tdvf.c', 'tdvf-hob.c'))
|
||||||
|
|
||||||
subdir('kvm')
|
subdir('kvm')
|
||||||
subdir('xen')
|
subdir('xen')
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user