Compare commits

..
12 Commits
Author SHA1 Message Date
Paolo Bonzini 9173d5d084 gitlab-ci: add manual job to run Coverity
Add a job that can be run, either manually or on a schedule, to upload
a build to Coverity Scan.  The job uses the run-coverity-scan script
in multiple phases of check, download tools and upload, in order to
avoid both wasting time (skip everything if you are above the upload
quota) and avoid filling the log with the progress of downloading
the tools.

The job is intended to run on a scheduled pipeline run, and scheduled
runs will not get any other job.  It requires two variables to be in
GitLab CI, COVERITY_TOKEN and COVERITY_EMAIL.  Those are already set up
in qemu-project's configuration as protected and masked variables.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-03-05 20:07:30 +01:00
Paolo Bonzini d8f4a7a80e run-coverity-scan: add --check-upload-only option
Add an option to check if upload is permitted without actually
attempting a build.  This can be useful to add a third outcome
beyond success and failure---namely, a CI job can self-cancel
if the uploading quota has been reached.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-03-05 12:32:09 +01:00
Paolo Bonzini c80a048f38 target/i386: remove mask from CCPrepare
With the introduction of TSTEQ and TSTNE the .mask field is always -1,
so remove all the now-unnecessary code.

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-03-05 12:32:09 +01:00
Paolo Bonzini af87044127 target/i386: use TSTEQ/TSTNE to check flags
The new conditions obviously come in handy when testing individual bits
of EFLAGS, and they make it possible to remove the .mask field of
CCPrepare.

Lowering to shift+and is done by the optimizer if necessary.

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-03-05 12:32:09 +01:00
Paolo Bonzini 395d5d09c7 target/i386: use TSTEQ/TSTNE to test low bits
When testing the sign bit or equality to zero of a partial register, it
is useful to use a single TSTEQ or TSTNE operation.  It can also be used
to test the parity flag, using bit 0 of the population count.

Do not do this for target_ulong-sized values however; the optimizer would
produce a comparison against zero anyway, and it avoids shifts by 64
which are undefined behavior.

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-03-05 12:32:09 +01:00
Paolo Bonzini ac056cbb54 mips: do not list individual devices from configs/
Add new "select" and "imply" directives if needed.  The resulting
config-devices.mak files are the same as before.
Builds without default devices will become much smaller
than before, and qtests fail (as expected, though suboptimal)
for mips64-softmmu because most tests do not use -nodefaults,
so remove it from build-without-defaults

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-03-05 12:32:09 +01:00
Paolo Bonzini f0060d4691 oslib-posix: fix memory leak in touch_all_pages
touch_all_pages() can return early, before creating threads.  In this case,
however, it leaks the MemsetContext that it has allocated at the
beginning of the function.

Reported by Coverity as CID 1534922.

Fixes: 04accf43df ("oslib-posix: initialize backend memory objects in parallel", 2024-02-06)
Reviewed-by: Mark Kanda <mark.kanda@oracle.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-03-05 12:32:09 +01:00
Paolo Bonzini 0170f3ea3d hw/intc/apic: fix memory leak
deliver_bitmask is allocated on the heap in apic_deliver(), but there
are many paths in the function that return before the corresponding
g_free() is reached.  Fix this by switching to g_autofree and, while at
it, also switch to g_new.  Do the same in apic_deliver_irq() as well
for consistency.

Fixes: b5ee0468e9 ("apic: add support for x2APIC mode", 2024-02-14)
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Bui Quang Minh <minhquangbui99@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-03-05 12:32:09 +01:00
Sven Schnelle 9ae56d2e46 hw/scsi/lsi53c895a: stop script on phase mismatch
Netbsd isn't happy with qemu lsi53c895a emulation:

cd0(esiop0:0:2:0): command with tag id 0 reset
esiop0: autoconfiguration error: phase mismatch without command
esiop0: autoconfiguration error: unhandled scsi interrupt, sist=0x80 sstat1=0x0 DSA=0x23a64b1 DSP=0x50

This is because lsi_bad_phase() triggers a phase mismatch, which
stops SCRIPT processing. However, after returning to
lsi_command_complete(), SCRIPT is restarted with lsi_resume_script().
Fix this by adding a return value to lsi_bad_phase(), and only resume
script processing when lsi_bad_phase() didn't trigger a host interrupt.

Signed-off-by: Sven Schnelle <svens@stackframe.org>
Tested-by: Helge Deller <deller@gmx.de>
Message-ID: <20240302214453.2071388-1-svens@stackframe.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-03-05 10:46:48 +01:00
Akihiko Odaki 6ed0b8431c meson: Remove --warn-common ldflag
--warn-common ldflag causes warnings for multiple definitions of
___asan_globals_registered when enabling AddressSanitizer with clang.
The warning is somewhat obsolete so just remove it.

The common block is used to allow duplicate definitions of uninitialized
global variables. In the past, GCC and clang used to place such
variables in a common block by default, which prevented programmers for
noticing accidental duplicate definitions. Commit 49237acdb7 ("Enable
ld flag --warn-common") added --warn-common ldflag so that ld warns in
such a case.

Today, both of GCC and clang don't use common blocks by default[1][2] so
any remaining use of common blocks should be intentional. Remove
--warn-common ldflag to suppress warnings for intentional use of
common blocks.

[1]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85678
[2]: https://reviews.llvm.org/D75056

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Message-ID: <20240304-common-v1-1-1a2005d1f350@daynix.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-03-05 10:46:48 +01:00
Dmitrii Gavrilov 50a715c77c system/qdev-monitor: move drain_call_rcu call under if (!dev) in qmp_device_add()
Original goal of addition of drain_call_rcu to qmp_device_add was to cover
the failure case of qdev_device_add. It seems call of drain_call_rcu was
misplaced in 7bed89958b what led to waiting for pending RCU callbacks
under happy path too. What led to overall performance degradation of
qmp_device_add.

In this patch call of drain_call_rcu moved under handling of failure of
qdev_device_add.

Signed-off-by: Dmitrii Gavrilov <ds-gavr@yandex-team.ru>
Message-ID: <20231103105602.90475-1-ds-gavr@yandex-team.ru>
Fixes: 7bed89958b ("device_core: use drain_call_rcu in in qmp_device_add", 2020-10-12)
Cc: qemu-stable@nongnu.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-03-05 10:46:48 +01:00
Sven Schnelle efb1c1d294 hw/scsi/lsi53c895a: add timer to scripts processing
HP-UX 10.20 seems to make the lsi53c895a spinning on a memory location
under certain circumstances. As the SCSI controller and CPU are not
running at the same time this loop will never finish. After some
time, the check loop interrupts with a unexpected device disconnect.
This works, but is slow because the kernel resets the scsi controller.
Instead of signaling UDC, start a timer and exit the loop. Until the
timer fires, the CPU can process instructions which might changes the
memory location.

The limit of instructions is also reduced because scripts running on
the SCSI processor are usually very short. This keeps the time until
the loop is exit short.

Suggested-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Sven Schnelle <svens@stackframe.org>
Message-ID: <20240229204407.1699260-1-svens@stackframe.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-03-05 10:46:47 +01:00
963 changed files with 9903 additions and 27857 deletions
+1 -5
View File
@@ -24,10 +24,6 @@ variables:
# Each script line from will be in a collapsible section in the job output
# and show the duration of each line.
FF_SCRIPT_SECTIONS: 1
# The project has a fairly fat GIT repo so we try and avoid bringing in things
# we don't need. The --filter options avoid blobs and tree references we aren't going to use
# and we also avoid fetching tags.
GIT_FETCH_EXTRA_FLAGS: --filter=blob:none --filter=tree:0 --no-tags --prune --quiet
interruptible: true
@@ -128,7 +124,7 @@ variables:
when: manual
# Jobs can run if any jobs they depend on were successful
- if: '$CI_PROJECT_NAMESPACE == $QEMU_CI_UPSTREAM && $CI_COMMIT_BRANCH =~ /staging-[[:digit:]]+\.[[:digit:]]/'
- if: '$QEMU_JOB_SKIPPED && $CI_PROJECT_NAMESPACE == $QEMU_CI_UPSTREAM && $CI_COMMIT_BRANCH =~ /staging-[[:digit:]]+\.[[:digit:]]/'
when: on_success
variables:
QEMU_CI_CONTAINER_TAG: $CI_COMMIT_REF_SLUG
+3 -4
View File
@@ -14,7 +14,6 @@
- export CCACHE_DIR="$CCACHE_BASEDIR/ccache"
- export CCACHE_MAXSIZE="500M"
- export PATH="$CCACHE_WRAPPERSDIR:$PATH"
- du -sh .git
- mkdir build
- cd build
- ccache --zero-stats
@@ -26,10 +25,10 @@
then
pyvenv/bin/meson configure . -Dbackend_max_links="$LD_JOBS" ;
fi || exit 1;
- $MAKE -j"$JOBS"
- make -j"$JOBS"
- if test -n "$MAKE_CHECK_ARGS";
then
$MAKE -j"$JOBS" $MAKE_CHECK_ARGS ;
make -j"$JOBS" $MAKE_CHECK_ARGS ;
fi
- ccache --show-stats
@@ -60,7 +59,7 @@
- cd build
- find . -type f -exec touch {} +
# Avoid recompiling by hiding ninja with NINJA=":"
- $MAKE NINJA=":" $MAKE_CHECK_ARGS
- make NINJA=":" $MAKE_CHECK_ARGS
.native_test_job_template:
extends: .common_test_job_template
+8 -13
View File
@@ -158,9 +158,9 @@ build-system-centos:
- .native_build_job_template
- .native_build_artifact_template
needs:
job: amd64-centos9-container
job: amd64-centos8-container
variables:
IMAGE: centos9
IMAGE: centos8
CONFIGURE_ARGS: --disable-nettle --enable-gcrypt --enable-vfio-user-server
--enable-modules --enable-trace-backends=dtrace --enable-docs
TARGETS: ppc64-softmmu or1k-softmmu s390x-softmmu
@@ -187,8 +187,6 @@ build-previous-qemu:
variables:
IMAGE: opensuse-leap
TARGETS: x86_64-softmmu aarch64-softmmu
# Override the default flags as we need more to grab the old version
GIT_FETCH_EXTRA_FLAGS: --prune --quiet
before_script:
- export QEMU_PREV_VERSION="$(sed 's/\([0-9.]*\)\.[0-9]*/v\1.0/' VERSION)"
- git remote add upstream https://gitlab.com/qemu-project/qemu
@@ -242,7 +240,7 @@ check-system-centos:
- job: build-system-centos
artifacts: true
variables:
IMAGE: centos9
IMAGE: centos8
MAKE_CHECK_ARGS: check
avocado-system-centos:
@@ -251,7 +249,7 @@ avocado-system-centos:
- job: build-system-centos
artifacts: true
variables:
IMAGE: centos9
IMAGE: centos8
MAKE_CHECK_ARGS: check-avocado
AVOCADO_TAGS: arch:ppc64 arch:or1k arch:s390x arch:x86_64 arch:rx
arch:sh4 arch:nios2
@@ -327,9 +325,9 @@ avocado-system-flaky:
build-tcg-disabled:
extends: .native_build_job_template
needs:
job: amd64-centos9-container
job: amd64-centos8-container
variables:
IMAGE: centos9
IMAGE: centos8
script:
- mkdir build
- cd build
@@ -575,9 +573,6 @@ tsan-build:
CONFIGURE_ARGS: --enable-tsan --cc=clang --cxx=clang++
--enable-trace-backends=ust --disable-slirp
TARGETS: x86_64-softmmu ppc64-softmmu riscv64-softmmu x86_64-linux-user
# Remove when we switch to a distro with clang >= 18
# https://github.com/google/sanitizers/issues/1716
MAKE: setarch -R make
# gcov is a GCC features
gcov:
@@ -654,9 +649,9 @@ build-tci:
build-without-defaults:
extends: .native_build_job_template
needs:
job: amd64-centos9-container
job: amd64-centos8-container
variables:
IMAGE: centos9
IMAGE: centos8
CONFIGURE_ARGS:
--without-default-devices
--without-default-features
+3 -2
View File
@@ -19,9 +19,10 @@ cwd = os.getcwd()
reponame = os.path.basename(cwd)
repourl = "https://gitlab.com/%s/%s.git" % (namespace, reponame)
print(f"adding upstream git repo @ {repourl}")
subprocess.check_call(["git", "remote", "add", "check-dco", repourl])
subprocess.check_call(["git", "fetch", "check-dco", "master"])
subprocess.check_call(["git", "fetch", "check-dco", "master"],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL)
ancestor = subprocess.check_output(["git", "merge-base",
"check-dco/master", "HEAD"],
+3 -2
View File
@@ -19,12 +19,13 @@ cwd = os.getcwd()
reponame = os.path.basename(cwd)
repourl = "https://gitlab.com/%s/%s.git" % (namespace, reponame)
print(f"adding upstream git repo @ {repourl}")
# GitLab CI environment does not give us any direct info about the
# base for the user's branch. We thus need to figure out a common
# ancestor between the user's branch and current git master.
subprocess.check_call(["git", "remote", "add", "check-patch", repourl])
subprocess.check_call(["git", "fetch", "check-patch", "master"])
subprocess.check_call(["git", "fetch", "check-patch", "master"],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL)
ancestor = subprocess.check_output(["git", "merge-base",
"check-patch/master", "HEAD"],
+1 -3
View File
@@ -13,7 +13,7 @@
.cirrus_build_job:
extends: .base_job_template
stage: build
image: registry.gitlab.com/libvirt/libvirt-ci/cirrus-run:latest
image: registry.gitlab.com/libvirt/libvirt-ci/cirrus-run:master
needs: []
# 20 mins larger than "timeout_in" in cirrus/build.yml
# as there's often a 5-10 minute delay before Cirrus CI
@@ -57,7 +57,6 @@ x64-freebsd-13-build:
CIRRUS_VM_RAM: 8G
UPDATE_COMMAND: pkg update; pkg upgrade -y
INSTALL_COMMAND: pkg install -y
CONFIGURE_ARGS: --target-list-exclude=arm-softmmu,i386-softmmu,microblaze-softmmu,mips64el-softmmu,mipsel-softmmu,mips-softmmu,ppc-softmmu,sh4eb-softmmu,xtensa-softmmu
TEST_TARGETS: check
aarch64-macos-13-base-build:
@@ -73,7 +72,6 @@ aarch64-macos-13-base-build:
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
CONFIGURE_ARGS: --target-list-exclude=arm-softmmu,i386-softmmu,microblazeel-softmmu,mips64-softmmu,mipsel-softmmu,mips-softmmu,ppc-softmmu,sh4-softmmu,xtensaeb-softmmu
TEST_TARGETS: check-unit check-block check-qapi-schema check-softfloat check-qtest-x86_64
aarch64-macos-14-base-build:
+2 -2
View File
@@ -1,10 +1,10 @@
include:
- local: '/.gitlab-ci.d/container-template.yml'
amd64-centos9-container:
amd64-centos8-container:
extends: .container_job_template
variables:
NAME: centos9
NAME: centos8
amd64-fedora-container:
extends: .container_job_template
+6
View File
@@ -22,6 +22,12 @@ arm64-debian-cross-container:
variables:
NAME: debian-arm64-cross
armel-debian-cross-container:
extends: .container_job_template
stage: containers
variables:
NAME: debian-armel-cross
armhf-debian-cross-container:
extends: .container_job_template
stage: containers
+7
View File
@@ -1,6 +1,13 @@
include:
- local: '/.gitlab-ci.d/crossbuild-template.yml'
cross-armel-user:
extends: .cross_user_build_job
needs:
job: armel-debian-cross-container
variables:
IMAGE: debian-armel-cross
cross-armhf-user:
extends: .cross_user_build_job
needs:
+3 -4
View File
@@ -10,14 +10,13 @@
# gitlab-runner. To avoid problems that gitlab-runner can cause while
# reusing the GIT repository, let's enable the clone strategy, which
# guarantees a fresh repository on each job run.
variables:
GIT_STRATEGY: clone
# All custom runners can extend this template to upload the testlog
# data as an artifact and also feed the junit report
.custom_runner_template:
extends: .base_job_template
variables:
GIT_STRATEGY: clone
GIT_FETCH_EXTRA_FLAGS: --no-tags --prune --quiet
artifacts:
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
expire_in: 7 days
@@ -29,7 +28,7 @@
junit: build/meson-logs/testlog.junit.xml
include:
- local: '/.gitlab-ci.d/custom-runners/ubuntu-22.04-s390x.yml'
- local: '/.gitlab-ci.d/custom-runners/ubuntu-20.04-s390x.yml'
- local: '/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml'
- local: '/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch32.yml'
- local: '/.gitlab-ci.d/custom-runners/centos-stream-8-x86_64.yml'
@@ -1,13 +1,13 @@
# All ubuntu-22.04 jobs should run successfully in an environment
# All ubuntu-20.04 jobs should run successfully in an environment
# setup by the scripts/ci/setup/build-environment.yml task
# "Install basic packages to build QEMU on Ubuntu 22.04"
# "Install basic packages to build QEMU on Ubuntu 20.04/20.04"
ubuntu-22.04-s390x-all-linux-static:
ubuntu-20.04-s390x-all-linux-static:
extends: .custom_runner_template
needs: []
stage: build
tags:
- ubuntu_22.04
- ubuntu_20.04
- s390x
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
@@ -23,12 +23,12 @@ ubuntu-22.04-s390x-all-linux-static:
- make --output-sync check-tcg
- make --output-sync -j`nproc` check
ubuntu-22.04-s390x-all:
ubuntu-20.04-s390x-all:
extends: .custom_runner_template
needs: []
stage: build
tags:
- ubuntu_22.04
- ubuntu_20.04
- s390x
timeout: 75m
rules:
@@ -42,12 +42,12 @@ ubuntu-22.04-s390x-all:
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check
ubuntu-22.04-s390x-alldbg:
ubuntu-20.04-s390x-alldbg:
extends: .custom_runner_template
needs: []
stage: build
tags:
- ubuntu_22.04
- ubuntu_20.04
- s390x
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
@@ -65,12 +65,12 @@ ubuntu-22.04-s390x-alldbg:
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check
ubuntu-22.04-s390x-clang:
ubuntu-20.04-s390x-clang:
extends: .custom_runner_template
needs: []
stage: build
tags:
- ubuntu_22.04
- ubuntu_20.04
- s390x
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
@@ -87,11 +87,11 @@ ubuntu-22.04-s390x-clang:
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check
ubuntu-22.04-s390x-tci:
ubuntu-20.04-s390x-tci:
needs: []
stage: build
tags:
- ubuntu_22.04
- ubuntu_20.04
- s390x
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
@@ -107,12 +107,12 @@ ubuntu-22.04-s390x-tci:
|| { cat config.log meson-logs/meson-log.txt; exit 1; }
- make --output-sync -j`nproc`
ubuntu-22.04-s390x-notcg:
ubuntu-20.04-s390x-notcg:
extends: .custom_runner_template
needs: []
stage: build
tags:
- ubuntu_22.04
- ubuntu_20.04
- s390x
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
+3 -3
View File
@@ -1,7 +1,9 @@
msys2-64bit:
extends: .base_job_template
tags:
- saas-windows-medium-amd64
- shared-windows
- windows
- windows-1809
cache:
key: "$CI_JOB_NAME"
paths:
@@ -26,8 +28,6 @@ msys2-64bit:
# qTests don't run successfully with "--without-default-devices",
# so let's exclude the qtests from CI for now.
TEST_ARGS: --no-suite qtest
# The Windows git is a bit older so override the default
GIT_FETCH_EXTRA_FLAGS: --no-tags --prune --quiet
artifacts:
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
expire_in: 7 days
+7 -7
View File
@@ -35,7 +35,7 @@ env:
- TEST_BUILD_CMD=""
- TEST_CMD="make check V=1"
# This is broadly a list of "mainline" system targets which have support across the major distros
- MAIN_SYSTEM_TARGETS="aarch64-softmmu,mips64-softmmu,ppc64-softmmu,riscv64-softmmu,s390x-softmmu,x86_64-softmmu"
- MAIN_SOFTMMU_TARGETS="aarch64-softmmu,mips64-softmmu,ppc64-softmmu,riscv64-softmmu,s390x-softmmu,x86_64-softmmu"
- CCACHE_SLOPPINESS="include_file_ctime,include_file_mtime"
- CCACHE_MAXSIZE=1G
- G_MESSAGES_DEBUG=error
@@ -114,7 +114,7 @@ jobs:
env:
- TEST_CMD="make check check-tcg V=1"
- CONFIG="--disable-containers --enable-fdt=system
--target-list=${MAIN_SYSTEM_TARGETS} --cxx=/bin/false"
--target-list=${MAIN_SOFTMMU_TARGETS} --cxx=/bin/false"
- UNRELIABLE=true
- name: "[ppc64] GCC check-tcg"
@@ -184,8 +184,8 @@ jobs:
- genisoimage
env:
- TEST_CMD="make check check-tcg V=1"
- CONFIG="--disable-containers
--target-list=hppa-softmmu,mips64-softmmu,ppc64-softmmu,riscv64-softmmu,s390x-softmmu,x86_64-softmmu"
- CONFIG="--disable-containers --enable-fdt=system
--target-list=${MAIN_SOFTMMU_TARGETS},s390x-linux-user"
- UNRELIABLE=true
script:
- BUILD_RC=0 && make -j${JOBS} || BUILD_RC=$?
@@ -220,12 +220,13 @@ jobs:
- libsnappy-dev
- libzstd-dev
- nettle-dev
- xfslibs-dev
- ninja-build
# Tests dependencies
- genisoimage
env:
- CONFIG="--disable-containers --audio-drv-list=sdl --disable-user
--target-list=arm-softmmu,avr-softmmu,microblaze-softmmu,sh4eb-softmmu,sparc64-softmmu,xtensaeb-softmmu"
- CONFIG="--disable-containers --enable-fdt=system --audio-drv-list=sdl
--disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS}"
- name: "[s390x] GCC (user)"
arch: s390x
@@ -239,7 +240,6 @@ jobs:
- flex
- bison
env:
- TEST_CMD="make check check-tcg V=1"
- CONFIG="--disable-containers --disable-system"
- name: "[s390x] Clang (disable-tcg)"
+10 -22
View File
@@ -316,6 +316,7 @@ F: tests/tcg/openrisc/
PowerPC TCG CPUs
M: Nicholas Piggin <npiggin@gmail.com>
M: Daniel Henrique Barboza <danielhb413@gmail.com>
R: Cédric Le Goater <clg@kaod.org>
L: qemu-ppc@nongnu.org
S: Odd Fixes
F: target/ppc/
@@ -467,6 +468,7 @@ F: target/mips/sysemu/
PPC KVM CPUs
M: Nicholas Piggin <npiggin@gmail.com>
R: Daniel Henrique Barboza <danielhb413@gmail.com>
R: Cédric Le Goater <clg@kaod.org>
S: Odd Fixes
F: target/ppc/kvm.c
@@ -1128,11 +1130,7 @@ M: Inès Varhol <ines.varhol@telecom-paris.fr>
L: qemu-arm@nongnu.org
S: Maintained
F: hw/arm/stm32l4x5_soc.c
F: hw/misc/stm32l4x5_exti.c
F: hw/misc/stm32l4x5_syscfg.c
F: hw/misc/stm32l4x5_rcc.c
F: hw/gpio/stm32l4x5_gpio.c
F: include/hw/*/stm32l4x5_*.h
F: include/hw/arm/stm32l4x5_soc.h
B-L475E-IOT01A IoT Node
M: Arnaud Minier <arnaud.minier@telecom-paris.fr>
@@ -1506,6 +1504,7 @@ F: tests/avocado/ppc_prep_40p.py
sPAPR (pseries)
M: Nicholas Piggin <npiggin@gmail.com>
R: Daniel Henrique Barboza <danielhb413@gmail.com>
R: Cédric Le Goater <clg@kaod.org>
R: David Gibson <david@gibson.dropbear.id.au>
R: Harsh Prateek Bora <harshpb@linux.ibm.com>
L: qemu-ppc@nongnu.org
@@ -1545,12 +1544,12 @@ F: pc-bios/skiboot.lid
F: tests/qtest/pnv*
pca955x
M: Glenn Miles <milesg@linux.ibm.com>
M: Glenn Miles <milesg@linux.vnet.ibm.com>
L: qemu-ppc@nongnu.org
L: qemu-arm@nongnu.org
S: Odd Fixes
F: hw/gpio/pca955*.c
F: include/hw/gpio/pca955*.h
F: hw/misc/pca955*.c
F: include/hw/misc/pca955*.h
virtex_ml507
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
@@ -1572,7 +1571,6 @@ F: hw/rtc/m41t80.c
F: pc-bios/canyonlands.dt[sb]
F: pc-bios/u-boot-sam460ex-20100605.bin
F: roms/u-boot-sam460ex
F: docs/system/ppc/amigang.rst
pegasos2
M: BALATON Zoltan <balaton@eik.bme.hu>
@@ -2170,7 +2168,7 @@ S: Supported
F: hw/vfio/*
F: include/hw/vfio/
F: docs/igd-assign.txt
F: docs/devel/migration/vfio.rst
F: docs/devel/vfio-migration.rst
vfio-ccw
M: Eric Farman <farman@linux.ibm.com>
@@ -2231,7 +2229,6 @@ F: qapi/virtio.json
F: net/vhost-user.c
F: include/hw/virtio/
F: docs/devel/virtio*
F: docs/devel/migration/virtio.rst
virtio-balloon
M: Michael S. Tsirkin <mst@redhat.com>
@@ -2406,7 +2403,6 @@ F: docs/system/devices/virtio-snd.rst
nvme
M: Keith Busch <kbusch@kernel.org>
M: Klaus Jensen <its@irrelevant.dk>
R: Jesper Devantier <foss@defmacro.it>
L: qemu-block@nongnu.org
S: Supported
F: hw/nvme/*
@@ -2503,12 +2499,6 @@ S: Maintained
F: hw/i2c/i2c_mux_pca954x.c
F: include/hw/i2c/i2c_mux_pca954x.h
pcf8574
M: Dmitrii Sharikhin <d.sharikhin@yadro.com>
S: Maintained
F: hw/gpio/pcf8574.c
F: include/gpio/pcf8574.h
Generic Loader
M: Alistair Francis <alistair@alistair23.me>
S: Maintained
@@ -3009,7 +2999,7 @@ F: include/qapi/error.h
F: include/qemu/error-report.h
F: qapi/error.json
F: util/error.c
F: util/error-report.c
F: util/qemu-error.c
F: scripts/coccinelle/err-bad-newline.cocci
F: scripts/coccinelle/error-use-after-free.cocci
F: scripts/coccinelle/error_propagate_null.cocci
@@ -3418,7 +3408,7 @@ F: migration/
F: scripts/vmstate-static-checker.py
F: tests/vmstate-static-checker-data/
F: tests/qtest/migration-test.c
F: docs/devel/migration/
F: docs/devel/migration.rst
F: qapi/migration.json
F: tests/migration/
F: util/userfaultfd.c
@@ -3438,7 +3428,6 @@ F: include/sysemu/dirtylimit.h
F: migration/dirtyrate.c
F: migration/dirtyrate.h
F: include/sysemu/dirtyrate.h
F: docs/devel/migration/dirty-limit.rst
Detached LUKS header
M: Hyman Huang <yong.huang@smartx.com>
@@ -3594,7 +3583,6 @@ F: util/iova-tree.c
elf2dmp
M: Viktor Prutyanov <viktor.prutyanov@phystech.edu>
R: Akihiko Odaki <akihiko.odaki@daynix.com>
S: Maintained
F: contrib/elf2dmp/
+2 -7
View File
@@ -141,13 +141,8 @@ MAKE.n = $(findstring n,$(firstword $(filter-out --%,$(MAKEFLAGS))))
MAKE.k = $(findstring k,$(firstword $(filter-out --%,$(MAKEFLAGS))))
MAKE.q = $(findstring q,$(firstword $(filter-out --%,$(MAKEFLAGS))))
MAKE.nq = $(if $(word 2, $(MAKE.n) $(MAKE.q)),nq)
NINJAFLAGS = \
$(if $V,-v) \
$(if $(MAKE.n), -n) \
$(if $(MAKE.k), -k0) \
$(filter-out -j, \
$(or $(filter -l% -j%, $(MAKEFLAGS)), \
$(if $(filter --jobserver-auth=%, $(MAKEFLAGS)),, -j1))) \
NINJAFLAGS = $(if $V,-v) $(if $(MAKE.n), -n) $(if $(MAKE.k), -k0) \
$(filter-out -j, $(lastword -j1 $(filter -l% -j%, $(MAKEFLAGS)))) \
-d keepdepfile
ninja-cmd-goals = $(or $(MAKECMDGOALS), all)
ninja-cmd-goals += $(foreach g, $(MAKECMDGOALS), $(.ninja-goals.$g))
+1 -1
View File
@@ -1 +1 @@
9.0.4
8.2.50
+20 -82
View File
@@ -69,9 +69,6 @@
#define KVM_GUESTDBG_BLOCKIRQ 0
#endif
/* Default num of memslots to be allocated when VM starts */
#define KVM_MEMSLOTS_NR_ALLOC_DEFAULT 16
struct KVMParkedVcpu {
unsigned long vcpu_id;
int kvm_fd;
@@ -166,57 +163,6 @@ void kvm_resample_fd_notify(int gsi)
}
}
/**
* kvm_slots_grow(): Grow the slots[] array in the KVMMemoryListener
*
* @kml: The KVMMemoryListener* to grow the slots[] array
* @nr_slots_new: The new size of slots[] array
*
* Returns: True if the array grows larger, false otherwise.
*/
static bool kvm_slots_grow(KVMMemoryListener *kml, unsigned int nr_slots_new)
{
unsigned int i, cur = kml->nr_slots_allocated;
KVMSlot *slots;
if (nr_slots_new > kvm_state->nr_slots) {
nr_slots_new = kvm_state->nr_slots;
}
if (cur >= nr_slots_new) {
/* Big enough, no need to grow, or we reached max */
return false;
}
if (cur == 0) {
slots = g_new0(KVMSlot, nr_slots_new);
} else {
assert(kml->slots);
slots = g_renew(KVMSlot, kml->slots, nr_slots_new);
/*
* g_renew() doesn't initialize extended buffers, however kvm
* memslots require fields to be zero-initialized. E.g. pointers,
* memory_size field, etc.
*/
memset(&slots[cur], 0x0, sizeof(slots[0]) * (nr_slots_new - cur));
}
for (i = cur; i < nr_slots_new; i++) {
slots[i].slot = i;
}
kml->slots = slots;
kml->nr_slots_allocated = nr_slots_new;
trace_kvm_slots_grow(cur, nr_slots_new);
return true;
}
static bool kvm_slots_double(KVMMemoryListener *kml)
{
return kvm_slots_grow(kml, kml->nr_slots_allocated * 2);
}
unsigned int kvm_get_max_memslots(void)
{
KVMState *s = KVM_STATE(current_accel());
@@ -245,26 +191,15 @@ unsigned int kvm_get_free_memslots(void)
/* Called with KVMMemoryListener.slots_lock held */
static KVMSlot *kvm_get_free_slot(KVMMemoryListener *kml)
{
unsigned int n;
KVMState *s = kvm_state;
int i;
for (i = 0; i < kml->nr_slots_allocated; i++) {
for (i = 0; i < s->nr_slots; i++) {
if (kml->slots[i].memory_size == 0) {
return &kml->slots[i];
}
}
/*
* If no free slots, try to grow first by doubling. Cache the old size
* here to avoid another round of search: if the grow succeeded, it
* means slots[] now must have the existing "n" slots occupied,
* followed by one or more free slots starting from slots[n].
*/
n = kml->nr_slots_allocated;
if (kvm_slots_double(kml)) {
return &kml->slots[n];
}
return NULL;
}
@@ -285,9 +220,10 @@ static KVMSlot *kvm_lookup_matching_slot(KVMMemoryListener *kml,
hwaddr start_addr,
hwaddr size)
{
KVMState *s = kvm_state;
int i;
for (i = 0; i < kml->nr_slots_allocated; i++) {
for (i = 0; i < s->nr_slots; i++) {
KVMSlot *mem = &kml->slots[i];
if (start_addr == mem->start_addr && size == mem->memory_size) {
@@ -329,7 +265,7 @@ int kvm_physical_memory_addr_from_host(KVMState *s, void *ram,
int i, ret = 0;
kvm_slots_lock();
for (i = 0; i < kml->nr_slots_allocated; i++) {
for (i = 0; i < s->nr_slots; i++) {
KVMSlot *mem = &kml->slots[i];
if (ram >= mem->ram && ram < mem->ram + mem->memory_size) {
@@ -1061,7 +997,7 @@ static int kvm_physical_log_clear(KVMMemoryListener *kml,
kvm_slots_lock();
for (i = 0; i < kml->nr_slots_allocated; i++) {
for (i = 0; i < s->nr_slots; i++) {
mem = &kml->slots[i];
/* Discard slots that are empty or do not overlap the section */
if (!mem->memory_size ||
@@ -1666,8 +1602,12 @@ static void kvm_log_sync_global(MemoryListener *l, bool last_stage)
/* Flush all kernel dirty addresses into KVMSlot dirty bitmap */
kvm_dirty_ring_flush();
/*
* TODO: make this faster when nr_slots is big while there are
* only a few used slots (small VMs).
*/
kvm_slots_lock();
for (i = 0; i < kml->nr_slots_allocated; i++) {
for (i = 0; i < s->nr_slots; i++) {
mem = &kml->slots[i];
if (mem->memory_size && mem->flags & KVM_MEM_LOG_DIRTY_PAGES) {
kvm_slot_sync_dirty_pages(mem);
@@ -1782,9 +1722,12 @@ void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml,
{
int i;
kml->slots = g_new0(KVMSlot, s->nr_slots);
kml->as_id = as_id;
kvm_slots_grow(kml, KVM_MEMSLOTS_NR_ALLOC_DEFAULT);
for (i = 0; i < s->nr_slots; i++) {
kml->slots[i].slot = i;
}
QSIMPLEQ_INIT(&kml->transaction_add);
QSIMPLEQ_INIT(&kml->transaction_del);
@@ -2056,17 +1999,12 @@ int kvm_irqchip_add_msi_route(KVMRouteChange *c, int vector, PCIDevice *dev)
return -EINVAL;
}
if (s->irq_routes->nr < s->gsi_count) {
trace_kvm_irqchip_add_msi_route(dev ? dev->name : (char *)"N/A",
vector, virq);
trace_kvm_irqchip_add_msi_route(dev ? dev->name : (char *)"N/A",
vector, virq);
kvm_add_routing_entry(s, &kroute);
kvm_arch_add_msi_route_post(&kroute, vector, dev);
c->changes++;
} else {
kvm_irqchip_release_virq(s, virq);
return -ENOSPC;
}
kvm_add_routing_entry(s, &kroute);
kvm_arch_add_msi_route_post(&kroute, vector, dev);
c->changes++;
return virq;
}
-1
View File
@@ -31,4 +31,3 @@ kvm_cpu_exec(void) ""
kvm_interrupt_exit_request(void) ""
kvm_io_window_exit(void) ""
kvm_run_exit_system_event(int cpu_index, uint32_t event_type) "cpu_index %d, system_even_type %"PRIu32
kvm_slots_grow(unsigned int old, unsigned int new) "%u -> %u"
+2 -1
View File
@@ -436,6 +436,7 @@ const void *HELPER(lookup_tb_ptr)(CPUArchState *env)
static inline TranslationBlock * QEMU_DISABLE_CFI
cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit)
{
CPUArchState *env = cpu_env(cpu);
uintptr_t ret;
TranslationBlock *last_tb;
const void *tb_ptr = itb->tc.ptr;
@@ -445,7 +446,7 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit)
}
qemu_thread_jit_execute();
ret = tcg_qemu_tb_exec(cpu_env(cpu), tb_ptr);
ret = tcg_qemu_tb_exec(env, tb_ptr);
cpu->neg.can_do_io = true;
qemu_plugin_disable_mem_helpers(cpu);
/*
+7 -28
View File
@@ -1145,11 +1145,14 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx,
" prot=%x idx=%d\n",
addr, full->phys_addr, prot, mmu_idx);
read_flags = full->tlb_fill_flags;
read_flags = 0;
if (full->lg_page_size < TARGET_PAGE_BITS) {
/* Repeat the MMU check and TLB fill on every access. */
read_flags |= TLB_INVALID_MASK;
}
if (full->attrs.byte_swap) {
read_flags |= TLB_BSWAP;
}
is_ram = memory_region_is_ram(section->mr);
is_romd = memory_region_is_romd(section->mr);
@@ -1453,8 +1456,9 @@ static int probe_access_internal(CPUState *cpu, vaddr addr,
flags |= full->slow_flags[access_type];
/* Fold all "mmio-like" bits into TLB_MMIO. This is not RAM. */
if (unlikely(flags & ~(TLB_WATCHPOINT | TLB_NOTDIRTY | TLB_CHECK_ALIGNED))
|| (access_type != MMU_INST_FETCH && force_mmio)) {
if (unlikely(flags & ~(TLB_WATCHPOINT | TLB_NOTDIRTY))
||
(access_type != MMU_INST_FETCH && force_mmio)) {
*phost = NULL;
return TLB_MMIO;
}
@@ -1835,31 +1839,6 @@ static bool mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi,
tcg_debug_assert((flags & TLB_BSWAP) == 0);
}
/*
* This alignment check differs from the one above, in that this is
* based on the atomicity of the operation. The intended use case is
* the ARM memory type field of each PTE, where access to pages with
* Device memory type require alignment.
*/
if (unlikely(flags & TLB_CHECK_ALIGNED)) {
MemOp size = l->memop & MO_SIZE;
switch (l->memop & MO_ATOM_MASK) {
case MO_ATOM_NONE:
size = MO_8;
break;
case MO_ATOM_IFALIGN_PAIR:
case MO_ATOM_WITHIN16_PAIR:
size = size ? size - 1 : 0;
break;
default:
break;
}
if (addr & ((1 << size) - 1)) {
cpu_unaligned_access(cpu, addr, type, l->mmu_idx, ra);
}
}
return crosspage;
}
+18 -57
View File
@@ -57,6 +57,12 @@
#include "exec/helper-info.c.inc"
#undef HELPER_H
#ifdef CONFIG_SOFTMMU
# define CONFIG_SOFTMMU_GATE 1
#else
# define CONFIG_SOFTMMU_GATE 0
#endif
/*
* plugin_cb_start TCG op args[]:
* 0: enum plugin_gen_from
@@ -127,28 +133,16 @@ static void gen_empty_udata_cb_no_rwg(void)
*/
static void gen_empty_inline_cb(void)
{
TCGv_i32 cpu_index = tcg_temp_ebb_new_i32();
TCGv_ptr cpu_index_as_ptr = tcg_temp_ebb_new_ptr();
TCGv_i64 val = tcg_temp_ebb_new_i64();
TCGv_ptr ptr = tcg_temp_ebb_new_ptr();
tcg_gen_ld_i32(cpu_index, tcg_env,
-offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index));
/* second operand will be replaced by immediate value */
tcg_gen_mul_i32(cpu_index, cpu_index, cpu_index);
tcg_gen_ext_i32_ptr(cpu_index_as_ptr, cpu_index);
tcg_gen_movi_ptr(ptr, 0);
tcg_gen_add_ptr(ptr, ptr, cpu_index_as_ptr);
tcg_gen_ld_i64(val, ptr, 0);
/* second operand will be replaced by immediate value */
tcg_gen_add_i64(val, val, val);
/* pass an immediate != 0 so that it doesn't get optimized away */
tcg_gen_addi_i64(val, val, 0xdeadface);
tcg_gen_st_i64(val, ptr, 0);
tcg_temp_free_ptr(ptr);
tcg_temp_free_i64(val);
tcg_temp_free_ptr(cpu_index_as_ptr);
tcg_temp_free_i32(cpu_index);
}
static void gen_empty_mem_cb(TCGv_i64 addr, uint32_t info)
@@ -296,37 +290,12 @@ static TCGOp *copy_const_ptr(TCGOp **begin_op, TCGOp *op, void *ptr)
return op;
}
static TCGOp *copy_ld_i32(TCGOp **begin_op, TCGOp *op)
{
return copy_op(begin_op, op, INDEX_op_ld_i32);
}
static TCGOp *copy_ext_i32_ptr(TCGOp **begin_op, TCGOp *op)
{
if (UINTPTR_MAX == UINT32_MAX) {
op = copy_op(begin_op, op, INDEX_op_mov_i32);
} else {
op = copy_op(begin_op, op, INDEX_op_ext_i32_i64);
}
return op;
}
static TCGOp *copy_add_ptr(TCGOp **begin_op, TCGOp *op)
{
if (UINTPTR_MAX == UINT32_MAX) {
op = copy_op(begin_op, op, INDEX_op_add_i32);
} else {
op = copy_op(begin_op, op, INDEX_op_add_i64);
}
return op;
}
static TCGOp *copy_ld_i64(TCGOp **begin_op, TCGOp *op)
{
if (TCG_TARGET_REG_BITS == 32) {
/* 2x ld_i32 */
op = copy_ld_i32(begin_op, op);
op = copy_ld_i32(begin_op, op);
op = copy_op(begin_op, op, INDEX_op_ld_i32);
op = copy_op(begin_op, op, INDEX_op_ld_i32);
} else {
/* ld_i64 */
op = copy_op(begin_op, op, INDEX_op_ld_i64);
@@ -362,13 +331,6 @@ static TCGOp *copy_add_i64(TCGOp **begin_op, TCGOp *op, uint64_t v)
return op;
}
static TCGOp *copy_mul_i32(TCGOp **begin_op, TCGOp *op, uint32_t v)
{
op = copy_op(begin_op, op, INDEX_op_mul_i32);
op->args[2] = tcgv_i32_arg(tcg_constant_i32(v));
return op;
}
static TCGOp *copy_st_ptr(TCGOp **begin_op, TCGOp *op)
{
if (UINTPTR_MAX == UINT32_MAX) {
@@ -434,19 +396,18 @@ static TCGOp *append_inline_cb(const struct qemu_plugin_dyn_cb *cb,
TCGOp *begin_op, TCGOp *op,
int *unused)
{
char *ptr = cb->inline_insn.entry.score->data->data;
size_t elem_size = g_array_get_element_size(
cb->inline_insn.entry.score->data);
size_t offset = cb->inline_insn.entry.offset;
/* const_ptr */
op = copy_const_ptr(&begin_op, op, cb->userp);
op = copy_ld_i32(&begin_op, op);
op = copy_mul_i32(&begin_op, op, elem_size);
op = copy_ext_i32_ptr(&begin_op, op);
op = copy_const_ptr(&begin_op, op, ptr + offset);
op = copy_add_ptr(&begin_op, op);
/* ld_i64 */
op = copy_ld_i64(&begin_op, op);
/* add_i64 */
op = copy_add_i64(&begin_op, op, cb->inline_insn.imm);
/* st_i64 */
op = copy_st_i64(&begin_op, op);
return op;
}
+2 -2
View File
@@ -712,7 +712,7 @@ static void tb_record(TranslationBlock *tb)
tb_page_addr_t paddr0 = tb_page_addr0(tb);
tb_page_addr_t paddr1 = tb_page_addr1(tb);
tb_page_addr_t pindex0 = paddr0 >> TARGET_PAGE_BITS;
tb_page_addr_t pindex1 = paddr1 >> TARGET_PAGE_BITS;
tb_page_addr_t pindex1 = paddr0 >> TARGET_PAGE_BITS;
assert(paddr0 != -1);
if (unlikely(paddr1 != -1) && pindex0 != pindex1) {
@@ -744,7 +744,7 @@ static void tb_remove(TranslationBlock *tb)
tb_page_addr_t paddr0 = tb_page_addr0(tb);
tb_page_addr_t paddr1 = tb_page_addr1(tb);
tb_page_addr_t pindex0 = paddr0 >> TARGET_PAGE_BITS;
tb_page_addr_t pindex1 = paddr1 >> TARGET_PAGE_BITS;
tb_page_addr_t pindex1 = paddr0 >> TARGET_PAGE_BITS;
assert(paddr0 != -1);
if (unlikely(paddr1 != -1) && pindex0 != pindex1) {
+1 -1
View File
@@ -109,7 +109,7 @@ static void rr_wait_io_event(void)
{
CPUState *cpu;
while (all_cpu_threads_idle()) {
while (all_cpu_threads_idle() && replay_can_wait()) {
rr_stop_kick_timer();
qemu_cond_wait_bql(first_cpu->halt_cond);
}
+1 -1
View File
@@ -634,7 +634,7 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
cpu->cflags_next_tb = curr_cflags(cpu) | CF_MEMI_ONLY | n;
if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
vaddr pc = cpu->cc->get_pc(cpu);
vaddr pc = log_pc(cpu, tb);
if (qemu_log_in_addr_range(pc)) {
qemu_log("cpu_io_recompile: rewound execution of TB to %016"
VADDR_PRIx "\n", pc);
+22 -25
View File
@@ -18,14 +18,20 @@
static void set_can_do_io(DisasContextBase *db, bool val)
{
QEMU_BUILD_BUG_ON(sizeof_field(CPUState, neg.can_do_io) != 1);
tcg_gen_st8_i32(tcg_constant_i32(val), tcg_env,
offsetof(ArchCPU, parent_obj.neg.can_do_io) -
offsetof(ArchCPU, env));
if (db->saved_can_do_io != val) {
db->saved_can_do_io = val;
QEMU_BUILD_BUG_ON(sizeof_field(CPUState, neg.can_do_io) != 1);
tcg_gen_st8_i32(tcg_constant_i32(val), tcg_env,
offsetof(ArchCPU, parent_obj.neg.can_do_io) -
offsetof(ArchCPU, env));
}
}
bool translator_io_start(DisasContextBase *db)
{
set_can_do_io(db, true);
/*
* Ensure that this instruction will be the last in the TB.
* The target may override this to something more forceful.
@@ -78,6 +84,13 @@ static TCGOp *gen_tb_start(DisasContextBase *db, uint32_t cflags)
- offsetof(ArchCPU, env));
}
/*
* cpu->neg.can_do_io is set automatically here at the beginning of
* each translation block. The cost is minimal, plus it would be
* very easy to forget doing it in the translator.
*/
set_can_do_io(db, db->max_insns == 1);
return icount_start_insn;
}
@@ -116,7 +129,6 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
{
uint32_t cflags = tb_cflags(tb);
TCGOp *icount_start_insn;
TCGOp *first_insn_start = NULL;
bool plugin_enabled;
/* Initialize DisasContext */
@@ -127,7 +139,7 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
db->num_insns = 0;
db->max_insns = *max_insns;
db->singlestep_enabled = cflags & CF_SINGLE_STEP;
db->insn_start = NULL;
db->saved_can_do_io = -1;
db->host_addr[0] = host_pc;
db->host_addr[1] = NULL;
@@ -145,10 +157,6 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
while (true) {
*max_insns = ++db->num_insns;
ops->insn_start(db, cpu);
db->insn_start = tcg_last_op();
if (first_insn_start == NULL) {
first_insn_start = db->insn_start;
}
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
if (plugin_enabled) {
@@ -161,6 +169,10 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
* done next -- either exiting this loop or locate the start of
* the next instruction.
*/
if (db->num_insns == db->max_insns) {
/* Accept I/O on the last instruction. */
set_can_do_io(db, true);
}
ops->translate_insn(db, cpu);
/*
@@ -193,21 +205,6 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
ops->tb_stop(db, cpu);
gen_tb_end(tb, cflags, icount_start_insn, db->num_insns);
/*
* Manage can_do_io for the translation block: set to false before
* the first insn and set to true before the last insn.
*/
if (db->num_insns == 1) {
tcg_debug_assert(first_insn_start == db->insn_start);
} else {
tcg_debug_assert(first_insn_start != db->insn_start);
tcg_ctx->emit_before_op = first_insn_start;
set_can_do_io(db, false);
}
tcg_ctx->emit_before_op = db->insn_start;
set_can_do_io(db, true);
tcg_ctx->emit_before_op = NULL;
if (plugin_enabled) {
plugin_gen_tb_end(cpu, db->num_insns);
}
+1 -1
View File
@@ -796,7 +796,7 @@ static int probe_access_internal(CPUArchState *env, vaddr addr,
if (guest_addr_valid_untagged(addr)) {
int page_flags = page_get_flags(addr);
if (page_flags & acc_flag) {
if (access_type != MMU_INST_FETCH
if ((acc_flag == PAGE_READ || acc_flag == PAGE_WRITE)
&& cpu_plugin_mem_cbs_enabled(env_cpu(env))) {
return TLB_MMIO;
}
-1
View File
@@ -15,7 +15,6 @@
#include "hw/xen/xen_native.h"
#include "hw/xen/xen-legacy-backend.h"
#include "hw/xen/xen_pt.h"
#include "hw/xen/xen_igd.h"
#include "chardev/char.h"
#include "qemu/accel.h"
#include "sysemu/cpus.h"
+5 -8
View File
@@ -23,7 +23,6 @@
#include "qemu/osdep.h"
#include "sysemu/cryptodev.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "standard-headers/linux/virtio_crypto.h"
#include "crypto/cipher.h"
@@ -397,8 +396,8 @@ static int cryptodev_builtin_create_session(
case VIRTIO_CRYPTO_HASH_CREATE_SESSION:
case VIRTIO_CRYPTO_MAC_CREATE_SESSION:
default:
error_report("Unsupported opcode :%" PRIu32 "",
sess_info->op_code);
error_setg(&local_error, "Unsupported opcode :%" PRIu32 "",
sess_info->op_code);
return -VIRTIO_CRYPTO_NOTSUPP;
}
@@ -428,9 +427,7 @@ static int cryptodev_builtin_close_session(
CRYPTODEV_BACKEND_BUILTIN(backend);
CryptoDevBackendBuiltinSession *session;
if (session_id >= MAX_NUM_SESSIONS || !builtin->sessions[session_id]) {
return -VIRTIO_CRYPTO_INVSESS;
}
assert(session_id < MAX_NUM_SESSIONS && builtin->sessions[session_id]);
session = builtin->sessions[session_id];
if (session->cipher) {
@@ -555,8 +552,8 @@ static int cryptodev_builtin_operation(
if (op_info->session_id >= MAX_NUM_SESSIONS ||
builtin->sessions[op_info->session_id] == NULL) {
error_report("Cannot find a valid session id: %" PRIu64 "",
op_info->session_id);
error_setg(&local_error, "Cannot find a valid session id: %" PRIu64 "",
op_info->session_id);
return -VIRTIO_CRYPTO_INVSESS;
}
-1
View File
@@ -43,7 +43,6 @@ static void iommufd_backend_finalize(Object *obj)
static void iommufd_backend_set_fd(Object *obj, const char *str, Error **errp)
{
ERRP_GUARD();
IOMMUFDBackend *be = IOMMUFD_BACKEND(obj);
int fd = -1;
+34 -62
View File
@@ -86,7 +86,6 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
BlockDriverState *parent,
const BdrvChildClass *child_class,
BdrvChildRole child_role,
bool parse_filename,
Error **errp);
static bool bdrv_recurse_has_child(BlockDriverState *bs,
@@ -535,9 +534,9 @@ typedef struct CreateCo {
int coroutine_fn bdrv_co_create(BlockDriver *drv, const char *filename,
QemuOpts *opts, Error **errp)
{
ERRP_GUARD();
int ret;
GLOBAL_STATE_CODE();
ERRP_GUARD();
if (!drv->bdrv_co_create_opts) {
error_setg(errp, "Driver '%s' does not support image creation",
@@ -634,7 +633,6 @@ int coroutine_fn bdrv_co_create_opts_simple(BlockDriver *drv,
QemuOpts *opts,
Error **errp)
{
ERRP_GUARD();
BlockBackend *blk;
QDict *options;
int64_t size = 0;
@@ -2000,7 +1998,6 @@ fail_opts:
static QDict *parse_json_filename(const char *filename, Error **errp)
{
ERRP_GUARD();
QObject *options_obj;
QDict *options;
int ret;
@@ -2059,8 +2056,7 @@ static void parse_json_protocol(QDict *options, const char **pfilename,
* block driver has been specified explicitly.
*/
static int bdrv_fill_options(QDict **options, const char *filename,
int *flags, bool allow_parse_filename,
Error **errp)
int *flags, Error **errp)
{
const char *drvname;
bool protocol = *flags & BDRV_O_PROTOCOL;
@@ -2102,7 +2098,7 @@ static int bdrv_fill_options(QDict **options, const char *filename,
if (protocol && filename) {
if (!qdict_haskey(*options, "filename")) {
qdict_put_str(*options, "filename", filename);
parse_filename = allow_parse_filename;
parse_filename = true;
} else {
error_setg(errp, "Can't specify 'file' and 'filename' options at "
"the same time");
@@ -3589,7 +3585,6 @@ int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
const char *bdref_key, Error **errp)
{
ERRP_GUARD();
char *backing_filename = NULL;
char *bdref_key_dot;
const char *reference = NULL;
@@ -3665,8 +3660,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
}
backing_hd = bdrv_open_inherit(backing_filename, reference, options, 0, bs,
&child_of_bds, bdrv_backing_role(bs), true,
errp);
&child_of_bds, bdrv_backing_role(bs), errp);
if (!backing_hd) {
bs->open_flags |= BDRV_O_NO_BACKING;
error_prepend(errp, "Could not open backing file: ");
@@ -3700,8 +3694,7 @@ free_exit:
static BlockDriverState *
bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref_key,
BlockDriverState *parent, const BdrvChildClass *child_class,
BdrvChildRole child_role, bool allow_none,
bool parse_filename, Error **errp)
BdrvChildRole child_role, bool allow_none, Error **errp)
{
BlockDriverState *bs = NULL;
QDict *image_options;
@@ -3732,8 +3725,7 @@ bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref_key,
}
bs = bdrv_open_inherit(filename, reference, image_options, 0,
parent, child_class, child_role, parse_filename,
errp);
parent, child_class, child_role, errp);
if (!bs) {
goto done;
}
@@ -3743,33 +3735,6 @@ done:
return bs;
}
static BdrvChild *bdrv_open_child_common(const char *filename,
QDict *options, const char *bdref_key,
BlockDriverState *parent,
const BdrvChildClass *child_class,
BdrvChildRole child_role,
bool allow_none, bool parse_filename,
Error **errp)
{
BlockDriverState *bs;
BdrvChild *child;
GLOBAL_STATE_CODE();
bs = bdrv_open_child_bs(filename, options, bdref_key, parent, child_class,
child_role, allow_none, parse_filename, errp);
if (bs == NULL) {
return NULL;
}
bdrv_graph_wrlock();
child = bdrv_attach_child(parent, bs, bdref_key, child_class, child_role,
errp);
bdrv_graph_wrunlock();
return child;
}
/*
* Opens a disk image whose options are given as BlockdevRef in another block
* device's options.
@@ -3793,15 +3758,27 @@ BdrvChild *bdrv_open_child(const char *filename,
BdrvChildRole child_role,
bool allow_none, Error **errp)
{
return bdrv_open_child_common(filename, options, bdref_key, parent,
child_class, child_role, allow_none, false,
errp);
BlockDriverState *bs;
BdrvChild *child;
GLOBAL_STATE_CODE();
bs = bdrv_open_child_bs(filename, options, bdref_key, parent, child_class,
child_role, allow_none, errp);
if (bs == NULL) {
return NULL;
}
bdrv_graph_wrlock();
child = bdrv_attach_child(parent, bs, bdref_key, child_class, child_role,
errp);
bdrv_graph_wrunlock();
return child;
}
/*
* This does mostly the same as bdrv_open_child(), but for opening the primary
* child of a node. A notable difference from bdrv_open_child() is that it
* enables filename parsing for protocol names (including json:).
* Wrapper on bdrv_open_child() for most popular case: open primary child of bs.
*
* @parent can move to a different AioContext in this function.
*/
@@ -3816,8 +3793,8 @@ int bdrv_open_file_child(const char *filename,
role = parent->drv->is_filter ?
(BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY) : BDRV_CHILD_IMAGE;
if (!bdrv_open_child_common(filename, options, bdref_key, parent,
&child_of_bds, role, false, true, errp))
if (!bdrv_open_child(filename, options, bdref_key, parent,
&child_of_bds, role, false, errp))
{
return -EINVAL;
}
@@ -3862,8 +3839,7 @@ BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp)
}
bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, 0, false,
errp);
bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, 0, errp);
obj = NULL;
qobject_unref(obj);
visit_free(v);
@@ -3875,7 +3851,6 @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
QDict *snapshot_options,
Error **errp)
{
ERRP_GUARD();
g_autofree char *tmp_filename = NULL;
int64_t total_size;
QemuOpts *opts = NULL;
@@ -3953,7 +3928,7 @@ static BlockDriverState * no_coroutine_fn
bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
int flags, BlockDriverState *parent,
const BdrvChildClass *child_class, BdrvChildRole child_role,
bool parse_filename, Error **errp)
Error **errp)
{
int ret;
BlockBackend *file = NULL;
@@ -4001,11 +3976,9 @@ bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
}
/* json: syntax counts as explicit options, as if in the QDict */
if (parse_filename) {
parse_json_protocol(options, &filename, &local_err);
if (local_err) {
goto fail;
}
parse_json_protocol(options, &filename, &local_err);
if (local_err) {
goto fail;
}
bs->explicit_options = qdict_clone_shallow(options);
@@ -4030,8 +4003,7 @@ bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
parent->open_flags, parent->options);
}
ret = bdrv_fill_options(&options, filename, &flags, parse_filename,
&local_err);
ret = bdrv_fill_options(&options, filename, &flags, &local_err);
if (ret < 0) {
goto fail;
}
@@ -4100,7 +4072,7 @@ bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
file_bs = bdrv_open_child_bs(filename, options, "file", bs,
&child_of_bds, BDRV_CHILD_IMAGE,
true, true, &local_err);
true, &local_err);
if (local_err) {
goto fail;
}
@@ -4249,7 +4221,7 @@ BlockDriverState *bdrv_open(const char *filename, const char *reference,
GLOBAL_STATE_CODE();
return bdrv_open_inherit(filename, reference, options, flags, NULL,
NULL, 0, true, errp);
NULL, 0, errp);
}
/* Return true if the NULL-terminated @list contains @str */
+2 -4
View File
@@ -899,10 +899,8 @@ static int blkio_file_open(BlockDriverState *bs, QDict *options, int flags,
}
bs->supported_write_flags = BDRV_REQ_FUA | BDRV_REQ_REGISTERED_BUF;
bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK;
#ifdef CONFIG_BLKIO_WRITE_ZEROS_FUA
bs->supported_zero_flags |= BDRV_REQ_FUA;
#endif
bs->supported_zero_flags = BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP |
BDRV_REQ_NO_FALLBACK;
qemu_mutex_init(&s->blkio_lock);
qemu_co_mutex_init(&s->bounce_lock);
+11 -7
View File
@@ -599,14 +599,14 @@ BlockDriverState *bdrv_next(BdrvNextIterator *it)
/* Must be called from the main loop */
assert(qemu_get_current_aio_context() == qemu_get_aio_context());
old_bs = it->bs;
/* First, return all root nodes of BlockBackends. In order to avoid
* returning a BDS twice when multiple BBs refer to it, we only return it
* if the BB is the first one in the parent list of the BDS. */
if (it->phase == BDRV_NEXT_BACKEND_ROOTS) {
BlockBackend *old_blk = it->blk;
old_bs = old_blk ? blk_bs(old_blk) : NULL;
do {
it->blk = blk_all_next(it->blk);
bs = it->blk ? blk_bs(it->blk) : NULL;
@@ -620,10 +620,11 @@ BlockDriverState *bdrv_next(BdrvNextIterator *it)
if (bs) {
bdrv_ref(bs);
bdrv_unref(old_bs);
it->bs = bs;
return bs;
}
it->phase = BDRV_NEXT_MONITOR_OWNED;
} else {
old_bs = it->bs;
}
/* Then return the monitor-owned BDSes without a BB attached. Ignore all
@@ -663,10 +664,13 @@ void bdrv_next_cleanup(BdrvNextIterator *it)
/* Must be called from the main loop */
assert(qemu_get_current_aio_context() == qemu_get_aio_context());
bdrv_unref(it->bs);
if (it->phase == BDRV_NEXT_BACKEND_ROOTS && it->blk) {
blk_unref(it->blk);
if (it->phase == BDRV_NEXT_BACKEND_ROOTS) {
if (it->blk) {
bdrv_unref(blk_bs(it->blk));
blk_unref(it->blk);
}
} else {
bdrv_unref(it->bs);
}
bdrv_next_reset(it);
+1 -3
View File
@@ -65,8 +65,7 @@ typedef struct BDRVCopyBeforeWriteState {
/*
* @frozen_read_reqs: current read requests for fleecing user in bs->file
* node. These areas must not be rewritten by guest. There can be multiple
* overlapping read requests.
* node. These areas must not be rewritten by guest.
*/
BlockReqList frozen_read_reqs;
@@ -408,7 +407,6 @@ out:
static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
ERRP_GUARD();
BDRVCopyBeforeWriteState *s = bs->opaque;
BdrvDirtyBitmap *bitmap = NULL;
int64_t cluster_size;
+12 -19
View File
@@ -1726,29 +1726,22 @@ static int bdrv_pad_request(BlockDriverState *bs,
return 0;
}
/*
* For prefetching in stream_populate(), no qiov is passed along, because
* only copy-on-read matters.
*/
if (*qiov) {
sliced_iov = qemu_iovec_slice(*qiov, *qiov_offset, *bytes,
&sliced_head, &sliced_tail,
&sliced_niov);
sliced_iov = qemu_iovec_slice(*qiov, *qiov_offset, *bytes,
&sliced_head, &sliced_tail,
&sliced_niov);
/* Guaranteed by bdrv_check_request32() */
assert(*bytes <= SIZE_MAX);
ret = bdrv_create_padded_qiov(bs, pad, sliced_iov, sliced_niov,
sliced_head, *bytes);
if (ret < 0) {
bdrv_padding_finalize(pad);
return ret;
}
*qiov = &pad->local_qiov;
*qiov_offset = 0;
/* Guaranteed by bdrv_check_request32() */
assert(*bytes <= SIZE_MAX);
ret = bdrv_create_padded_qiov(bs, pad, sliced_iov, sliced_niov,
sliced_head, *bytes);
if (ret < 0) {
bdrv_padding_finalize(pad);
return ret;
}
*bytes += pad->head + pad->tail;
*offset -= pad->head;
*qiov = &pad->local_qiov;
*qiov_offset = 0;
if (padded) {
*padded = true;
}
+4 -6
View File
@@ -479,9 +479,9 @@ static unsigned mirror_perform(MirrorBlockJob *s, int64_t offset,
return bytes_handled;
}
static void coroutine_fn GRAPH_UNLOCKED mirror_iteration(MirrorBlockJob *s)
static void coroutine_fn GRAPH_RDLOCK mirror_iteration(MirrorBlockJob *s)
{
BlockDriverState *source;
BlockDriverState *source = s->mirror_top_bs->backing->bs;
MirrorOp *pseudo_op;
int64_t offset;
/* At least the first dirty chunk is mirrored in one iteration. */
@@ -489,10 +489,6 @@ static void coroutine_fn GRAPH_UNLOCKED mirror_iteration(MirrorBlockJob *s)
bool write_zeroes_ok = bdrv_can_write_zeroes_with_unmap(blk_bs(s->target));
int max_io_bytes = MAX(s->buf_size / MAX_IN_FLIGHT, MAX_IO_BYTES);
bdrv_graph_co_rdlock();
source = s->mirror_top_bs->backing->bs;
bdrv_graph_co_rdunlock();
bdrv_dirty_bitmap_lock(s->dirty_bitmap);
offset = bdrv_dirty_iter_next(s->dbi);
if (offset < 0) {
@@ -1070,7 +1066,9 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
mirror_wait_for_free_in_flight_slot(s);
continue;
} else if (cnt != 0) {
bdrv_graph_co_rdlock();
mirror_iteration(s);
bdrv_graph_co_rdunlock();
}
}
+1 -2
View File
@@ -402,8 +402,7 @@ void hmp_nbd_server_start(Monitor *mon, const QDict *qdict)
goto exit;
}
nbd_server_start(addr, NULL, NULL, NBD_DEFAULT_MAX_CONNECTIONS,
&local_err);
nbd_server_start(addr, NULL, NULL, 0, &local_err);
qapi_free_SocketAddress(addr);
if (local_err != NULL) {
goto exit;
-1
View File
@@ -852,7 +852,6 @@ static coroutine_fn int nbd_co_do_receive_one_chunk(
BDRVNBDState *s, uint64_t cookie, bool only_structured,
int *request_ret, QEMUIOVector *qiov, void **payload, Error **errp)
{
ERRP_GUARD();
int ret;
int i = COOKIE_TO_INDEX(cookie);
void *local_payload = NULL;
-3
View File
@@ -168,7 +168,6 @@ static QemuOptsList runtime_opts = {
static bool nvme_init_queue(BDRVNVMeState *s, NVMeQueue *q,
unsigned nentries, size_t entry_bytes, Error **errp)
{
ERRP_GUARD();
size_t bytes;
int r;
@@ -222,7 +221,6 @@ static NVMeQueuePair *nvme_create_queue_pair(BDRVNVMeState *s,
unsigned idx, size_t size,
Error **errp)
{
ERRP_GUARD();
int i, r;
NVMeQueuePair *q;
uint64_t prp_list_iova;
@@ -537,7 +535,6 @@ static int nvme_admin_cmd_sync(BlockDriverState *bs, NvmeCmd *cmd)
/* Returns true on success, false on failure. */
static bool nvme_identify(BlockDriverState *bs, int namespace, Error **errp)
{
ERRP_GUARD();
BDRVNVMeState *s = bs->opaque;
bool ret = false;
QEMU_AUTO_VFREE union {
+7 -9
View File
@@ -46,11 +46,11 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
bool flat,
Error **errp)
{
ERRP_GUARD();
ImageInfo **p_image_info;
ImageInfo *backing_info;
BlockDriverState *backing;
BlockDeviceInfo *info;
ERRP_GUARD();
if (!bs->drv) {
error_setg(errp, "Block device %s is ejected", bs->node_name);
@@ -330,8 +330,8 @@ void bdrv_query_image_info(BlockDriverState *bs,
bool skip_implicit_filters,
Error **errp)
{
ERRP_GUARD();
ImageInfo *info;
ERRP_GUARD();
info = g_new0(ImageInfo, 1);
bdrv_do_query_node_info(bs, qapi_ImageInfo_base(info), errp);
@@ -382,10 +382,10 @@ void bdrv_query_block_graph_info(BlockDriverState *bs,
BlockGraphInfo **p_info,
Error **errp)
{
ERRP_GUARD();
BlockGraphInfo *info;
BlockChildInfoList **children_list_tail;
BdrvChild *c;
ERRP_GUARD();
info = g_new0(BlockGraphInfo, 1);
bdrv_do_query_node_info(bs, qapi_BlockGraphInfo_base(info), errp);
@@ -742,15 +742,15 @@ void bdrv_snapshot_dump(QEMUSnapshotInfo *sn)
char *sizing = NULL;
if (!sn) {
qemu_printf("%-7s %-16s %8s %19s %15s %10s",
"ID", "TAG", "VM_SIZE", "DATE", "VM_CLOCK", "ICOUNT");
qemu_printf("%-10s%-17s%8s%20s%13s%11s",
"ID", "TAG", "VM SIZE", "DATE", "VM CLOCK", "ICOUNT");
} else {
g_autoptr(GDateTime) date = g_date_time_new_from_unix_local(sn->date_sec);
g_autofree char *date_buf = g_date_time_format(date, "%Y-%m-%d %H:%M:%S");
secs = sn->vm_clock_nsec / 1000000000;
snprintf(clock_buf, sizeof(clock_buf),
"%04d:%02d:%02d.%03d",
"%02d:%02d:%02d.%03d",
(int)(secs / 3600),
(int)((secs / 60) % 60),
(int)(secs % 60),
@@ -759,10 +759,8 @@ void bdrv_snapshot_dump(QEMUSnapshotInfo *sn)
if (sn->icount != -1ULL) {
snprintf(icount_buf, sizeof(icount_buf),
"%"PRId64, sn->icount);
} else {
snprintf(icount_buf, sizeof(icount_buf), "--");
}
qemu_printf("%-7s %-16s %8s %19s %15s %10s",
qemu_printf("%-9s %-16s %8s%20s%13s%11s",
sn->id_str, sn->name,
sizing,
date_buf,
-1
View File
@@ -1710,7 +1710,6 @@ bool coroutine_fn qcow2_co_can_store_new_dirty_bitmap(BlockDriverState *bs,
uint32_t granularity,
Error **errp)
{
ERRP_GUARD();
BDRVQcow2State *s = bs->opaque;
BdrvDirtyBitmap *bitmap;
uint64_t bitmap_directory_size = 0;
+1 -18
View File
@@ -1636,22 +1636,7 @@ qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
goto fail;
}
if (open_data_file && (flags & BDRV_O_NO_IO)) {
/*
* Don't open the data file for 'qemu-img info' so that it can be used
* to verify that an untrusted qcow2 image doesn't refer to external
* files.
*
* Note: This still makes has_data_file() return true.
*/
if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) {
s->data_file = NULL;
} else {
s->data_file = bs->file;
}
qdict_extract_subqdict(options, NULL, "data-file.");
qdict_del(options, "data-file");
} else if (open_data_file) {
if (open_data_file) {
/* Open external data file */
bdrv_graph_co_rdunlock();
s->data_file = bdrv_co_open_child(NULL, options, "data-file", bs,
@@ -3498,7 +3483,6 @@ static uint64_t qcow2_opt_get_refcount_bits_del(QemuOpts *opts, int version,
static int coroutine_fn GRAPH_UNLOCKED
qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
{
ERRP_GUARD();
BlockdevCreateOptionsQcow2 *qcow2_opts;
QDict *options;
@@ -4299,7 +4283,6 @@ static int coroutine_fn GRAPH_RDLOCK
qcow2_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
{
ERRP_GUARD();
BDRVQcow2State *s = bs->opaque;
uint64_t old_length;
int64_t new_l1_size;
-1
View File
@@ -1579,7 +1579,6 @@ bdrv_qed_co_change_backing_file(BlockDriverState *bs, const char *backing_file,
static void coroutine_fn GRAPH_RDLOCK
bdrv_qed_co_invalidate_cache(BlockDriverState *bs, Error **errp)
{
ERRP_GUARD();
BDRVQEDState *s = bs->opaque;
int ret;
+2 -2
View File
@@ -111,7 +111,7 @@ raw_apply_options(BlockDriverState *bs, BDRVRawState *s, uint64_t offset,
if (offset > real_size) {
error_setg(errp, "Offset (%" PRIu64 ") cannot be greater than "
"size of the containing file (%" PRId64 ")",
offset, real_size);
s->offset, real_size);
return -EINVAL;
}
@@ -119,7 +119,7 @@ raw_apply_options(BlockDriverState *bs, BDRVRawState *s, uint64_t offset,
error_setg(errp, "The sum of offset (%" PRIu64 ") and size "
"(%" PRIu64 ") has to be smaller or equal to the "
" actual size of the containing file (%" PRId64 ")",
offset, size, real_size);
s->offset, s->size, real_size);
return -EINVAL;
}
+2
View File
@@ -20,6 +20,8 @@
void reqlist_init_req(BlockReqList *reqs, BlockReq *req, int64_t offset,
int64_t bytes)
{
assert(!reqlist_find_conflict(reqs, offset, bytes));
*req = (BlockReq) {
.offset = offset,
.bytes = bytes,
-2
View File
@@ -566,7 +566,6 @@ int bdrv_all_delete_snapshot(const char *name,
bool has_devices, strList *devices,
Error **errp)
{
ERRP_GUARD();
g_autoptr(GList) bdrvs = NULL;
GList *iterbdrvs;
@@ -606,7 +605,6 @@ int bdrv_all_goto_snapshot(const char *name,
bool has_devices, strList *devices,
Error **errp)
{
ERRP_GUARD();
g_autoptr(GList) bdrvs = NULL;
GList *iterbdrvs;
int ret;
-1
View File
@@ -738,7 +738,6 @@ static int coroutine_fn GRAPH_UNLOCKED
vdi_co_do_create(BlockdevCreateOptions *create_options, size_t block_size,
Error **errp)
{
ERRP_GUARD();
BlockdevCreateOptionsVdi *vdi_opts;
int ret = 0;
uint64_t bytes = 0;
-1
View File
@@ -1147,7 +1147,6 @@ static int GRAPH_RDLOCK
vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
Error **errp)
{
ERRP_GUARD();
int ret;
int matches;
char access[11];
+14 -13
View File
@@ -1369,9 +1369,8 @@ static int open_file(BDRVVVFATState* s,mapping_t* mapping)
return -1;
vvfat_close_current_file(s);
s->current_fd = fd;
s->current_mapping = mapping;
}
s->current_mapping = mapping;
return 0;
}
@@ -1409,9 +1408,7 @@ read_cluster_directory:
assert(s->current_fd);
offset = s->cluster_size *
((cluster_num - s->current_mapping->begin)
+ s->current_mapping->info.file.offset);
offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
return -3;
s->cluster=s->cluster_buffer;
@@ -1881,6 +1878,7 @@ get_cluster_count_for_direntry(BDRVVVFATState* s, direntry_t* direntry, const ch
uint32_t cluster_num = begin_of_direntry(direntry);
uint32_t offset = 0;
int first_mapping_index = -1;
mapping_t* mapping = NULL;
const char* basename2 = NULL;
@@ -1931,9 +1929,8 @@ get_cluster_count_for_direntry(BDRVVVFATState* s, direntry_t* direntry, const ch
(mapping->mode & MODE_DIRECTORY) == 0) {
/* was modified in qcow */
if (offset != s->cluster_size
* ((cluster_num - mapping->begin)
+ mapping->info.file.offset)) {
if (offset != mapping->info.file.offset + s->cluster_size
* (cluster_num - mapping->begin)) {
/* offset of this cluster in file chain has changed */
abort();
copy_it = 1;
@@ -1942,9 +1939,14 @@ get_cluster_count_for_direntry(BDRVVVFATState* s, direntry_t* direntry, const ch
if (strcmp(basename, basename2))
copy_it = 1;
first_mapping_index = array_index(&(s->mapping), mapping);
}
if (mapping->first_mapping_index != first_mapping_index
&& mapping->info.file.offset > 0) {
abort();
copy_it = 1;
}
assert(mapping->first_mapping_index == -1
|| mapping->info.file.offset > 0);
/* need to write out? */
if (!was_modified && is_file(direntry)) {
@@ -2402,7 +2404,7 @@ static int commit_mappings(BDRVVVFATState* s,
(mapping->end - mapping->begin);
} else
next_mapping->info.file.offset = mapping->info.file.offset +
(mapping->end - mapping->begin);
mapping->end - mapping->begin;
mapping = next_mapping;
}
@@ -2523,9 +2525,8 @@ commit_one_file(BDRVVVFATState* s, int dir_index, uint32_t offset)
return -1;
}
for (i = 0; i < offset; i += s->cluster_size) {
for (i = s->cluster_size; i < offset; i += s->cluster_size)
c = modified_fat_get(s, c);
}
fd = qemu_open_old(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
if (fd < 0) {
+6 -53
View File
@@ -21,18 +21,12 @@
#include "io/channel-socket.h"
#include "io/net-listener.h"
typedef struct NBDConn {
QIOChannelSocket *cioc;
QLIST_ENTRY(NBDConn) next;
} NBDConn;
typedef struct NBDServerData {
QIONetListener *listener;
QCryptoTLSCreds *tlscreds;
char *tlsauthz;
uint32_t max_connections;
uint32_t connections;
QLIST_HEAD(, NBDConn) conns;
} NBDServerData;
static NBDServerData *nbd_server;
@@ -57,14 +51,6 @@ int nbd_server_max_connections(void)
static void nbd_blockdev_client_closed(NBDClient *client, bool ignored)
{
NBDConn *conn = nbd_client_owner(client);
assert(qemu_in_main_thread() && nbd_server);
object_unref(OBJECT(conn->cioc));
QLIST_REMOVE(conn, next);
g_free(conn);
nbd_client_put(client);
assert(nbd_server->connections > 0);
nbd_server->connections--;
@@ -74,56 +60,31 @@ static void nbd_blockdev_client_closed(NBDClient *client, bool ignored)
static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc,
gpointer opaque)
{
NBDConn *conn = g_new0(NBDConn, 1);
assert(qemu_in_main_thread() && nbd_server);
nbd_server->connections++;
object_ref(OBJECT(cioc));
conn->cioc = cioc;
QLIST_INSERT_HEAD(&nbd_server->conns, conn, next);
nbd_update_server_watch(nbd_server);
qio_channel_set_name(QIO_CHANNEL(cioc), "nbd-server");
/* TODO - expose handshake timeout as QMP option */
nbd_client_new(cioc, NBD_DEFAULT_HANDSHAKE_MAX_SECS,
nbd_server->tlscreds, nbd_server->tlsauthz,
nbd_blockdev_client_closed, conn);
nbd_client_new(cioc, nbd_server->tlscreds, nbd_server->tlsauthz,
nbd_blockdev_client_closed);
}
static void nbd_update_server_watch(NBDServerData *s)
{
if (s->listener) {
if (!s->max_connections || s->connections < s->max_connections) {
qio_net_listener_set_client_func(s->listener, nbd_accept, NULL,
NULL);
} else {
qio_net_listener_set_client_func(s->listener, NULL, NULL, NULL);
}
if (!s->max_connections || s->connections < s->max_connections) {
qio_net_listener_set_client_func(s->listener, nbd_accept, NULL, NULL);
} else {
qio_net_listener_set_client_func(s->listener, NULL, NULL, NULL);
}
}
static void nbd_server_free(NBDServerData *server)
{
NBDConn *conn, *tmp;
if (!server) {
return;
}
/*
* Forcefully close the listener socket, and any clients that have
* not yet disconnected on their own.
*/
qio_net_listener_disconnect(server->listener);
object_unref(OBJECT(server->listener));
server->listener = NULL;
QLIST_FOREACH_SAFE(conn, &server->conns, next, tmp) {
qio_channel_shutdown(QIO_CHANNEL(conn->cioc), QIO_CHANNEL_SHUTDOWN_BOTH,
NULL);
}
AIO_WAIT_WHILE_UNLOCKED(NULL, server->connections > 0);
if (server->tlscreds) {
object_unref(OBJECT(server->tlscreds));
}
@@ -207,10 +168,6 @@ void nbd_server_start(SocketAddress *addr, const char *tls_creds,
void nbd_server_start_options(NbdServerOptions *arg, Error **errp)
{
if (!arg->has_max_connections) {
arg->max_connections = NBD_DEFAULT_MAX_CONNECTIONS;
}
nbd_server_start(arg->addr, arg->tls_creds, arg->tls_authz,
arg->max_connections, errp);
}
@@ -223,10 +180,6 @@ void qmp_nbd_server_start(SocketAddressLegacy *addr,
{
SocketAddress *addr_flat = socket_address_flatten(addr);
if (!has_max_connections) {
max_connections = NBD_DEFAULT_MAX_CONNECTIONS;
}
nbd_server_start(addr_flat, tls_creds, tls_authz, max_connections, errp);
qapi_free_SocketAddress(addr_flat);
}
+3 -3
View File
@@ -1395,8 +1395,7 @@ static void external_snapshot_action(TransactionAction *action,
bdrv_drained_begin(state->old_bs);
if (!bdrv_is_inserted(state->old_bs)) {
error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM,
bdrv_get_device_or_node_name(state->old_bs));
error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
return;
}
@@ -2253,7 +2252,8 @@ void coroutine_fn qmp_block_resize(const char *device, const char *node_name,
}
bdrv_graph_co_rdlock();
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_RESIZE, errp)) {
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_RESIZE, NULL)) {
error_setg(errp, QERR_DEVICE_IN_USE, device);
bdrv_graph_co_rdunlock();
return;
}
+1 -1
View File
@@ -641,7 +641,7 @@ static abi_long do_bsd_readlink(CPUArchState *env, abi_long arg1,
}
if (strcmp(p1, "/proc/curproc/file") == 0) {
CPUState *cpu = env_cpu(env);
TaskState *ts = get_task_state(cpu);
TaskState *ts = (TaskState *)cpu->opaque;
strncpy(p2, ts->bprm->fullpath, arg3);
ret = MIN((abi_long)strlen(ts->bprm->fullpath), arg3);
} else {
+3 -3
View File
@@ -208,7 +208,7 @@ static inline abi_long do_freebsd_fork(void *cpu_env)
*/
set_second_rval(cpu_env, child_flag);
fork_end(ret);
fork_end(child_flag);
return ret;
}
@@ -252,7 +252,7 @@ static inline abi_long do_freebsd_rfork(void *cpu_env, abi_long flags)
* value: 0 for parent process, 1 for child process.
*/
set_second_rval(cpu_env, child_flag);
fork_end(ret);
fork_end(child_flag);
return ret;
@@ -285,7 +285,7 @@ static inline abi_long do_freebsd_pdfork(void *cpu_env, abi_ulong target_fdp,
* value: 0 for parent process, 1 for child process.
*/
set_second_rval(cpu_env, child_flag);
fork_end(ret);
fork_end(child_flag);
return ret;
}
+3 -8
View File
@@ -113,13 +113,10 @@ void fork_start(void)
start_exclusive();
cpu_list_lock();
mmap_fork_start();
gdbserver_fork_start();
}
void fork_end(pid_t pid)
void fork_end(int child)
{
bool child = pid == 0;
if (child) {
CPUState *cpu, *next_cpu;
/*
@@ -137,12 +134,10 @@ void fork_end(pid_t pid)
* state, so we don't need to end_exclusive() here.
*/
qemu_init_cpu_list();
get_task_state(thread_cpu)->ts_tid = qemu_get_thread_id();
gdbserver_fork_end(thread_cpu, pid);
gdbserver_fork(thread_cpu);
} else {
mmap_fork_end(child);
cpu_list_unlock();
gdbserver_fork_end(thread_cpu, pid);
end_exclusive();
}
}
@@ -606,7 +601,7 @@ int main(int argc, char **argv)
if (gdbstub) {
gdbserver_start(gdbstub);
gdb_handlesig(cpu, 0, NULL, NULL, 0);
gdb_handlesig(cpu, 0);
}
cpu_loop(env);
/* never exits */
+1 -6
View File
@@ -117,11 +117,6 @@ typedef struct TaskState {
struct target_sigaltstack sigaltstack_used;
} __attribute__((aligned(16))) TaskState;
static inline TaskState *get_task_state(CPUState *cs)
{
return cs->opaque;
}
void stop_all_tasks(void);
extern const char *interp_prefix;
extern const char *qemu_uname_release;
@@ -192,7 +187,7 @@ void cpu_loop(CPUArchState *env);
char *target_strerror(int err);
int get_osversion(void);
void fork_start(void);
void fork_end(pid_t pid);
void fork_end(int child);
#include "qemu/log.h"
+13 -15
View File
@@ -27,9 +27,6 @@
#include "hw/core/tcg-cpu-ops.h"
#include "host-signal.h"
/* target_siginfo_t must fit in gdbstub's siginfo save area. */
QEMU_BUILD_BUG_ON(sizeof(target_siginfo_t) > MAX_SIGINFO_LENGTH);
static struct target_sigaction sigact_table[TARGET_NSIG];
static void host_signal_handler(int host_sig, siginfo_t *info, void *puc);
static void target_to_host_sigset_internal(sigset_t *d,
@@ -322,7 +319,7 @@ void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
int block_signals(void)
{
TaskState *ts = get_task_state(thread_cpu);
TaskState *ts = (TaskState *)thread_cpu->opaque;
sigset_t set;
/*
@@ -362,7 +359,7 @@ void dump_core_and_abort(int target_sig)
{
CPUState *cpu = thread_cpu;
CPUArchState *env = cpu_env(cpu);
TaskState *ts = get_task_state(cpu);
TaskState *ts = cpu->opaque;
int core_dumped = 0;
int host_sig;
struct sigaction act;
@@ -424,7 +421,7 @@ void queue_signal(CPUArchState *env, int sig, int si_type,
target_siginfo_t *info)
{
CPUState *cpu = env_cpu(env);
TaskState *ts = get_task_state(cpu);
TaskState *ts = cpu->opaque;
trace_user_queue_signal(env, sig);
@@ -466,19 +463,20 @@ static int fatal_signal(int sig)
void force_sig_fault(int sig, int code, abi_ulong addr)
{
CPUState *cpu = thread_cpu;
CPUArchState *env = cpu_env(cpu);
target_siginfo_t info = {};
info.si_signo = sig;
info.si_errno = 0;
info.si_code = code;
info.si_addr = addr;
queue_signal(cpu_env(cpu), sig, QEMU_SI_FAULT, &info);
queue_signal(env, sig, QEMU_SI_FAULT, &info);
}
static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
{
CPUState *cpu = thread_cpu;
TaskState *ts = get_task_state(cpu);
TaskState *ts = cpu->opaque;
target_siginfo_t tinfo;
ucontext_t *uc = puc;
struct emulated_sigtable *k;
@@ -587,7 +585,7 @@ static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
/* compare to kern/kern_sig.c sys_sigaltstack() and kern_sigaltstack() */
abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
{
TaskState *ts = get_task_state(thread_cpu);
TaskState *ts = (TaskState *)thread_cpu->opaque;
int ret;
target_stack_t oss;
@@ -716,7 +714,7 @@ int do_sigaction(int sig, const struct target_sigaction *act,
static inline abi_ulong get_sigframe(struct target_sigaction *ka,
CPUArchState *env, size_t frame_size)
{
TaskState *ts = get_task_state(thread_cpu);
TaskState *ts = (TaskState *)thread_cpu->opaque;
abi_ulong sp;
/* Use default user stack */
@@ -791,7 +789,7 @@ static int reset_signal_mask(target_ucontext_t *ucontext)
int i;
sigset_t blocked;
target_sigset_t target_set;
TaskState *ts = get_task_state(thread_cpu);
TaskState *ts = (TaskState *)thread_cpu->opaque;
for (i = 0; i < TARGET_NSIG_WORDS; i++) {
__get_user(target_set.__bits[i], &ucontext->uc_sigmask.__bits[i]);
@@ -841,7 +839,7 @@ badframe:
void signal_init(void)
{
TaskState *ts = get_task_state(thread_cpu);
TaskState *ts = (TaskState *)thread_cpu->opaque;
struct sigaction act;
struct sigaction oact;
int i;
@@ -880,7 +878,7 @@ static void handle_pending_signal(CPUArchState *env, int sig,
struct emulated_sigtable *k)
{
CPUState *cpu = env_cpu(env);
TaskState *ts = get_task_state(cpu);
TaskState *ts = cpu->opaque;
struct target_sigaction *sa;
int code;
sigset_t set;
@@ -892,7 +890,7 @@ static void handle_pending_signal(CPUArchState *env, int sig,
k->pending = 0;
sig = gdb_handlesig(cpu, sig, NULL, &k->info, sizeof(k->info));
sig = gdb_handlesig(cpu, sig);
if (!sig) {
sa = NULL;
handler = TARGET_SIG_IGN;
@@ -969,7 +967,7 @@ void process_pending_signals(CPUArchState *env)
int sig;
sigset_t *blocked_set, set;
struct emulated_sigtable *k;
TaskState *ts = get_task_state(cpu);
TaskState *ts = cpu->opaque;
while (qatomic_read(&ts->signal_pending)) {
sigfillset(&set);
+6 -7
View File
@@ -199,18 +199,13 @@ bool qemu_chr_fe_init(CharBackend *b, Chardev *s, Error **errp)
MuxChardev *d = MUX_CHARDEV(s);
if (d->mux_cnt >= MAX_MUX) {
error_setg(errp,
"too many uses of multiplexed chardev '%s'"
" (maximum is " stringify(MAX_MUX) ")",
s->label);
return false;
goto unavailable;
}
d->backends[d->mux_cnt] = b;
tag = d->mux_cnt++;
} else if (s->be) {
error_setg(errp, "chardev '%s' is already in use", s->label);
return false;
goto unavailable;
} else {
s->be = b;
}
@@ -220,6 +215,10 @@ bool qemu_chr_fe_init(CharBackend *b, Chardev *s, Error **errp)
b->tag = tag;
b->chr = s;
return true;
unavailable:
error_setg(errp, QERR_DEVICE_IN_USE, s->label);
return false;
}
void qemu_chr_fe_deinit(CharBackend *b, bool del)
+5 -42
View File
@@ -33,7 +33,6 @@ typedef struct IOWatchPoll {
IOCanReadHandler *fd_can_read;
GSourceFunc fd_read;
void *opaque;
GMainContext *context;
} IOWatchPoll;
static IOWatchPoll *io_watch_poll_from_source(GSource *source)
@@ -51,55 +50,28 @@ static gboolean io_watch_poll_prepare(GSource *source,
return FALSE;
}
/*
* We do not register the QIOChannel watch as a child GSource.
* The 'prepare' function on the parent GSource will be
* skipped if a child GSource's 'prepare' function indicates
* readiness. We need this prepare function be guaranteed
* to run on *every* iteration of the main loop, because
* it is critical to ensure we remove the QIOChannel watch
* if 'fd_can_read' indicates the frontend cannot receive
* more data.
*/
if (now_active) {
iwp->src = qio_channel_create_watch(
iwp->ioc, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL);
g_source_set_callback(iwp->src, iwp->fd_read, iwp->opaque, NULL);
g_source_attach(iwp->src, iwp->context);
} else {
g_source_destroy(iwp->src);
g_source_add_child_source(source, iwp->src);
g_source_unref(iwp->src);
} else {
g_source_remove_child_source(source, iwp->src);
iwp->src = NULL;
}
return FALSE;
}
static gboolean io_watch_poll_check(GSource *source)
{
return FALSE;
}
static gboolean io_watch_poll_dispatch(GSource *source, GSourceFunc callback,
gpointer user_data)
{
abort();
}
static void io_watch_poll_finalize(GSource *source)
{
IOWatchPoll *iwp = io_watch_poll_from_source(source);
if (iwp->src) {
g_source_destroy(iwp->src);
g_source_unref(iwp->src);
iwp->src = NULL;
}
return G_SOURCE_CONTINUE;
}
static GSourceFuncs io_watch_poll_funcs = {
.prepare = io_watch_poll_prepare,
.check = io_watch_poll_check,
.dispatch = io_watch_poll_dispatch,
.finalize = io_watch_poll_finalize,
};
GSource *io_add_watch_poll(Chardev *chr,
@@ -119,7 +91,6 @@ GSource *io_add_watch_poll(Chardev *chr,
iwp->ioc = ioc;
iwp->fd_read = (GSourceFunc) fd_read;
iwp->src = NULL;
iwp->context = context;
name = g_strdup_printf("chardev-iowatch-%s", chr->label);
g_source_set_name((GSource *)iwp, name);
@@ -130,18 +101,10 @@ GSource *io_add_watch_poll(Chardev *chr,
return (GSource *)iwp;
}
static void io_remove_watch_poll(GSource *source)
{
IOWatchPoll *iwp;
iwp = io_watch_poll_from_source(source);
g_source_destroy(&iwp->parent);
}
void remove_fd_in_watch(Chardev *chr)
{
if (chr->gsource) {
io_remove_watch_poll(chr->gsource);
g_source_destroy(chr->gsource);
chr->gsource = NULL;
}
}
+3 -19
View File
@@ -496,9 +496,9 @@ static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
s->max_size <= 0) {
return TRUE;
}
len = sizeof(buf);
if (len > s->max_size) {
len = s->max_size;
len = tcp_chr_read_poll(opaque);
if (len > sizeof(buf)) {
len = sizeof(buf);
}
size = tcp_chr_recv(chr, (void *)buf, len);
if (size == 0 || (size == -1 && errno != EAGAIN)) {
@@ -601,22 +601,6 @@ static void update_ioc_handlers(SocketChardev *s)
remove_hup_source(s);
s->hup_source = qio_channel_create_watch(s->ioc, G_IO_HUP);
/*
* poll() is liable to return POLLHUP even when there is
* still incoming data available to read on the FD. If
* we have the hup_source at the same priority as the
* main io_add_watch_poll GSource, then we might end up
* processing the POLLHUP event first, closing the FD,
* and as a result silently discard data we should have
* read.
*
* By setting the hup_source to G_PRIORITY_DEFAULT + 1,
* we ensure that io_add_watch_poll GSource will always
* be dispatched first, thus guaranteeing we will be
* able to process all incoming data before closing the
* FD
*/
g_source_set_priority(s->hup_source, G_PRIORITY_DEFAULT + 1);
g_source_set_callback(s->hup_source, (GSourceFunc)tcp_chr_hup,
chr, NULL);
g_source_attach(s->hup_source, chr->gcontext);
-4
View File
@@ -41,7 +41,6 @@
/* init terminal so that we can grab keys */
static struct termios oldtty;
static int old_fd0_flags;
static int old_fd1_flags;
static bool stdio_in_use;
static bool stdio_allow_signal;
static bool stdio_echo_state;
@@ -51,8 +50,6 @@ static void term_exit(void)
if (stdio_in_use) {
tcsetattr(0, TCSANOW, &oldtty);
fcntl(0, F_SETFL, old_fd0_flags);
fcntl(1, F_SETFL, old_fd1_flags);
stdio_in_use = false;
}
}
@@ -105,7 +102,6 @@ static void qemu_chr_open_stdio(Chardev *chr,
stdio_in_use = true;
old_fd0_flags = fcntl(0, F_GETFL);
old_fd1_flags = fcntl(1, F_GETFL);
tcgetattr(0, &oldtty);
if (!g_unix_set_fd_nonblocking(0, true, NULL)) {
error_setg_errno(errp, errno, "Failed to set FD nonblocking");
-5
View File
@@ -33,7 +33,6 @@
struct WinStdioChardev {
Chardev parent;
HANDLE hStdIn;
DWORD dwOldMode;
HANDLE hInputReadyEvent;
HANDLE hInputDoneEvent;
HANDLE hInputThread;
@@ -160,7 +159,6 @@ static void qemu_chr_open_stdio(Chardev *chr,
}
is_console = GetConsoleMode(stdio->hStdIn, &dwMode) != 0;
stdio->dwOldMode = dwMode;
if (is_console) {
if (qemu_add_wait_object(stdio->hStdIn,
@@ -223,9 +221,6 @@ static void char_win_stdio_finalize(Object *obj)
{
WinStdioChardev *stdio = WIN_STDIO_CHARDEV(obj);
if (stdio->hStdIn != INVALID_HANDLE_VALUE) {
SetConsoleMode(stdio->hStdIn, stdio->dwOldMode);
}
if (stdio->hInputReadyEvent != INVALID_HANDLE_VALUE) {
CloseHandle(stdio->hInputReadyEvent);
}
Vendored
+2 -11
View File
@@ -411,9 +411,7 @@ else
# Using uname is really broken, but it is just a fallback for architectures
# that are going to use TCI anyway
cpu=$(uname -m)
if test "$host_os" != "bogus"; then
echo "WARNING: unrecognized host CPU, proceeding with 'uname -m' output '$cpu'"
fi
echo "WARNING: unrecognized host CPU, proceeding with 'uname -m' output '$cpu'"
fi
# Normalise host CPU name to the values used by Meson cross files and in source
@@ -764,7 +762,7 @@ for opt do
--*) meson_option_parse "$opt" "$optarg"
;;
# Pass through -Dxxxx options to meson
-D*) meson_option_add "$opt"
-D*) meson_options="$meson_options $opt"
;;
esac
done
@@ -896,13 +894,6 @@ EOF
exit 0
fi
# Now that we are sure that the user did not only want to print the --help
# information, we should double-check that the C compiler really works:
write_c_skeleton
if ! compile_object ; then
error_exit "C compiler \"$cc\" either does not exist or does not work."
fi
# Remove old dependency files to make sure that they get properly regenerated
rm -f ./*/config-devices.mak.d
+26 -37
View File
@@ -22,7 +22,7 @@ static struct pa_block *pa_space_find_block(struct pa_space *ps, uint64_t pa)
return NULL;
}
static void *pa_space_resolve(struct pa_space *ps, uint64_t pa)
static uint8_t *pa_space_resolve(struct pa_space *ps, uint64_t pa)
{
struct pa_block *block = pa_space_find_block(ps, pa);
@@ -33,19 +33,6 @@ static void *pa_space_resolve(struct pa_space *ps, uint64_t pa)
return block->addr + (pa - block->paddr);
}
static bool pa_space_read64(struct pa_space *ps, uint64_t pa, uint64_t *value)
{
uint64_t *resolved = pa_space_resolve(ps, pa);
if (!resolved) {
return false;
}
*value = *resolved;
return true;
}
static void pa_block_align(struct pa_block *b)
{
uint64_t low_align = ((b->paddr - 1) | ELF2DMP_PAGE_MASK) + 1 - b->paddr;
@@ -70,7 +57,7 @@ static void pa_block_align(struct pa_block *b)
b->paddr += low_align;
}
void pa_space_create(struct pa_space *ps, QEMU_Elf *qemu_elf)
int pa_space_create(struct pa_space *ps, QEMU_Elf *qemu_elf)
{
Elf64_Half phdr_nr = elf_getphdrnum(qemu_elf->map);
Elf64_Phdr *phdr = elf64_getphdr(qemu_elf->map);
@@ -88,12 +75,11 @@ void pa_space_create(struct pa_space *ps, QEMU_Elf *qemu_elf)
ps->block = g_new(struct pa_block, ps->block_nr);
for (i = 0; i < phdr_nr; i++) {
if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset < qemu_elf->size) {
if (phdr[i].p_type == PT_LOAD) {
ps->block[block_i] = (struct pa_block) {
.addr = (uint8_t *)qemu_elf->map + phdr[i].p_offset,
.paddr = phdr[i].p_paddr,
.size = MIN(phdr[i].p_filesz,
qemu_elf->size - phdr[i].p_offset),
.size = phdr[i].p_filesz,
};
pa_block_align(&ps->block[block_i]);
block_i = ps->block[block_i].size ? (block_i + 1) : block_i;
@@ -101,6 +87,8 @@ void pa_space_create(struct pa_space *ps, QEMU_Elf *qemu_elf)
}
ps->block_nr = block_i;
return 0;
}
void pa_space_destroy(struct pa_space *ps)
@@ -120,20 +108,19 @@ void va_space_create(struct va_space *vs, struct pa_space *ps, uint64_t dtb)
va_space_set_dtb(vs, dtb);
}
static bool get_pml4e(struct va_space *vs, uint64_t va, uint64_t *value)
static uint64_t get_pml4e(struct va_space *vs, uint64_t va)
{
uint64_t pa = (vs->dtb & 0xffffffffff000) | ((va & 0xff8000000000) >> 36);
return pa_space_read64(vs->ps, pa, value);
return *(uint64_t *)pa_space_resolve(vs->ps, pa);
}
static bool get_pdpi(struct va_space *vs, uint64_t va, uint64_t pml4e,
uint64_t *value)
static uint64_t get_pdpi(struct va_space *vs, uint64_t va, uint64_t pml4e)
{
uint64_t pdpte_paddr = (pml4e & 0xffffffffff000) |
((va & 0x7FC0000000) >> 27);
return pa_space_read64(vs->ps, pdpte_paddr, value);
return *(uint64_t *)pa_space_resolve(vs->ps, pdpte_paddr);
}
static uint64_t pde_index(uint64_t va)
@@ -146,12 +133,11 @@ static uint64_t pdba_base(uint64_t pdpe)
return pdpe & 0xFFFFFFFFFF000;
}
static bool get_pgd(struct va_space *vs, uint64_t va, uint64_t pdpe,
uint64_t *value)
static uint64_t get_pgd(struct va_space *vs, uint64_t va, uint64_t pdpe)
{
uint64_t pgd_entry = pdba_base(pdpe) + pde_index(va) * 8;
return pa_space_read64(vs->ps, pgd_entry, value);
return *(uint64_t *)pa_space_resolve(vs->ps, pgd_entry);
}
static uint64_t pte_index(uint64_t va)
@@ -164,12 +150,11 @@ static uint64_t ptba_base(uint64_t pde)
return pde & 0xFFFFFFFFFF000;
}
static bool get_pte(struct va_space *vs, uint64_t va, uint64_t pgd,
uint64_t *value)
static uint64_t get_pte(struct va_space *vs, uint64_t va, uint64_t pgd)
{
uint64_t pgd_val = ptba_base(pgd) + pte_index(va) * 8;
return pa_space_read64(vs->ps, pgd_val, value);
return *(uint64_t *)pa_space_resolve(vs->ps, pgd_val);
}
static uint64_t get_paddr(uint64_t va, uint64_t pte)
@@ -201,11 +186,13 @@ static uint64_t va_space_va2pa(struct va_space *vs, uint64_t va)
{
uint64_t pml4e, pdpe, pgd, pte;
if (!get_pml4e(vs, va, &pml4e) || !is_present(pml4e)) {
pml4e = get_pml4e(vs, va);
if (!is_present(pml4e)) {
return INVALID_PA;
}
if (!get_pdpi(vs, va, pml4e, &pdpe) || !is_present(pdpe)) {
pdpe = get_pdpi(vs, va, pml4e);
if (!is_present(pdpe)) {
return INVALID_PA;
}
@@ -213,7 +200,8 @@ static uint64_t va_space_va2pa(struct va_space *vs, uint64_t va)
return get_1GB_paddr(va, pdpe);
}
if (!get_pgd(vs, va, pdpe, &pgd) || !is_present(pgd)) {
pgd = get_pgd(vs, va, pdpe);
if (!is_present(pgd)) {
return INVALID_PA;
}
@@ -221,7 +209,8 @@ static uint64_t va_space_va2pa(struct va_space *vs, uint64_t va)
return get_2MB_paddr(va, pgd);
}
if (!get_pte(vs, va, pgd, &pte) || !is_present(pte)) {
pte = get_pte(vs, va, pgd);
if (!is_present(pte)) {
return INVALID_PA;
}
@@ -239,8 +228,8 @@ void *va_space_resolve(struct va_space *vs, uint64_t va)
return pa_space_resolve(vs->ps, pa);
}
bool va_space_rw(struct va_space *vs, uint64_t addr,
void *buf, size_t size, int is_write)
int va_space_rw(struct va_space *vs, uint64_t addr,
void *buf, size_t size, int is_write)
{
while (size) {
uint64_t page = addr & ELF2DMP_PFN_MASK;
@@ -251,7 +240,7 @@ bool va_space_rw(struct va_space *vs, uint64_t addr,
ptr = va_space_resolve(vs, addr);
if (!ptr) {
return false;
return 1;
}
if (is_write) {
@@ -265,5 +254,5 @@ bool va_space_rw(struct va_space *vs, uint64_t addr,
addr += s;
}
return true;
return 0;
}
+3 -3
View File
@@ -33,13 +33,13 @@ struct va_space {
struct pa_space *ps;
};
void pa_space_create(struct pa_space *ps, QEMU_Elf *qemu_elf);
int pa_space_create(struct pa_space *ps, QEMU_Elf *qemu_elf);
void pa_space_destroy(struct pa_space *ps);
void va_space_create(struct va_space *vs, struct pa_space *ps, uint64_t dtb);
void va_space_set_dtb(struct va_space *vs, uint64_t dtb);
void *va_space_resolve(struct va_space *vs, uint64_t va);
bool va_space_rw(struct va_space *vs, uint64_t addr,
void *buf, size_t size, int is_write);
int va_space_rw(struct va_space *vs, uint64_t addr,
void *buf, size_t size, int is_write);
#endif /* ADDRSPACE_H */
+7 -5
View File
@@ -9,18 +9,19 @@
#include <curl/curl.h>
#include "download.h"
bool download_url(const char *name, const char *url)
int download_url(const char *name, const char *url)
{
bool success = false;
int err = 0;
FILE *file;
CURL *curl = curl_easy_init();
if (!curl) {
return false;
return 1;
}
file = fopen(name, "wb");
if (!file) {
err = 1;
goto out_curl;
}
@@ -32,12 +33,13 @@ bool download_url(const char *name, const char *url)
|| curl_easy_perform(curl) != CURLE_OK) {
unlink(name);
fclose(file);
err = 1;
} else {
success = !fclose(file);
err = fclose(file);
}
out_curl:
curl_easy_cleanup(curl);
return success;
return err;
}
+1 -1
View File
@@ -8,6 +8,6 @@
#ifndef DOWNLOAD_H
#define DOWNLOAD_H
bool download_url(const char *name, const char *url);
int download_url(const char *name, const char *url);
#endif /* DOWNLOAD_H */
+93 -75
View File
@@ -6,7 +6,6 @@
*/
#include "qemu/osdep.h"
#include "qemu/bitops.h"
#include "err.h"
#include "addrspace.h"
@@ -48,6 +47,11 @@ static const uint64_t SharedUserData = 0xfffff78000000000;
s ? printf(#s" = 0x%016"PRIx64"\n", s) :\
eprintf("Failed to resolve "#s"\n"), s)
static uint64_t rol(uint64_t x, uint64_t y)
{
return (x << y) | (x >> (64 - y));
}
/*
* Decoding algorithm can be found in Volatility project
*/
@@ -60,7 +64,7 @@ static void kdbg_decode(uint64_t *dst, uint64_t *src, size_t size,
uint64_t block;
block = src[i];
block = rol64(block ^ kwn, kwn);
block = rol(block ^ kwn, (uint8_t)kwn);
block = __builtin_bswap64(block ^ kdbe) ^ kwa;
dst[i] = block;
}
@@ -75,9 +79,9 @@ static KDDEBUGGER_DATA64 *get_kdbg(uint64_t KernBase, struct pdb_reader *pdb,
bool decode = false;
uint64_t kwn, kwa, KdpDataBlockEncoded;
if (!va_space_rw(vs,
KdDebuggerDataBlock + offsetof(KDDEBUGGER_DATA64, Header),
&kdbg_hdr, sizeof(kdbg_hdr), 0)) {
if (va_space_rw(vs,
KdDebuggerDataBlock + offsetof(KDDEBUGGER_DATA64, Header),
&kdbg_hdr, sizeof(kdbg_hdr), 0)) {
eprintf("Failed to extract KDBG header\n");
return NULL;
}
@@ -93,8 +97,8 @@ static KDDEBUGGER_DATA64 *get_kdbg(uint64_t KernBase, struct pdb_reader *pdb,
return NULL;
}
if (!va_space_rw(vs, KiWaitNever, &kwn, sizeof(kwn), 0) ||
!va_space_rw(vs, KiWaitAlways, &kwa, sizeof(kwa), 0)) {
if (va_space_rw(vs, KiWaitNever, &kwn, sizeof(kwn), 0) ||
va_space_rw(vs, KiWaitAlways, &kwa, sizeof(kwa), 0)) {
return NULL;
}
@@ -118,7 +122,7 @@ static KDDEBUGGER_DATA64 *get_kdbg(uint64_t KernBase, struct pdb_reader *pdb,
kdbg = g_malloc(kdbg_hdr.Size);
if (!va_space_rw(vs, KdDebuggerDataBlock, kdbg, kdbg_hdr.Size, 0)) {
if (va_space_rw(vs, KdDebuggerDataBlock, kdbg, kdbg_hdr.Size, 0)) {
eprintf("Failed to extract entire KDBG\n");
g_free(kdbg);
return NULL;
@@ -182,13 +186,13 @@ static void win_context_init_from_qemu_cpu_state(WinContext64 *ctx,
* Finds paging-structure hierarchy base,
* if previously set doesn't give access to kernel structures
*/
static bool fix_dtb(struct va_space *vs, QEMU_Elf *qe)
static int fix_dtb(struct va_space *vs, QEMU_Elf *qe)
{
/*
* Firstly, test previously set DTB.
*/
if (va_space_resolve(vs, SharedUserData)) {
return true;
return 0;
}
/*
@@ -202,7 +206,7 @@ static bool fix_dtb(struct va_space *vs, QEMU_Elf *qe)
va_space_set_dtb(vs, s->cr[3]);
printf("DTB 0x%016"PRIx64" has been found from CPU #%zu"
" as system task CR3\n", vs->dtb, i);
return va_space_resolve(vs, SharedUserData);
return !(va_space_resolve(vs, SharedUserData));
}
}
@@ -216,16 +220,16 @@ static bool fix_dtb(struct va_space *vs, QEMU_Elf *qe)
uint64_t *cr3 = va_space_resolve(vs, Prcb + 0x7000);
if (!cr3) {
return false;
return 1;
}
va_space_set_dtb(vs, *cr3);
printf("DirectoryTableBase = 0x%016"PRIx64" has been found from CPU #0"
" as interrupt handling CR3\n", vs->dtb);
return va_space_resolve(vs, SharedUserData);
return !(va_space_resolve(vs, SharedUserData));
}
return true;
return 1;
}
static void try_merge_runs(struct pa_space *ps,
@@ -264,10 +268,9 @@ static void try_merge_runs(struct pa_space *ps,
}
}
static bool fill_header(WinDumpHeader64 *hdr, struct pa_space *ps,
struct va_space *vs, uint64_t KdDebuggerDataBlock,
KDDEBUGGER_DATA64 *kdbg, uint64_t KdVersionBlock,
int nr_cpus)
static int fill_header(WinDumpHeader64 *hdr, struct pa_space *ps,
struct va_space *vs, uint64_t KdDebuggerDataBlock,
KDDEBUGGER_DATA64 *kdbg, uint64_t KdVersionBlock, int nr_cpus)
{
uint32_t *suite_mask = va_space_resolve(vs, SharedUserData +
KUSD_OFFSET_SUITE_MASK);
@@ -280,12 +283,12 @@ static bool fill_header(WinDumpHeader64 *hdr, struct pa_space *ps,
QEMU_BUILD_BUG_ON(KUSD_OFFSET_PRODUCT_TYPE >= ELF2DMP_PAGE_SIZE);
if (!suite_mask || !product_type) {
return false;
return 1;
}
if (!va_space_rw(vs, KdVersionBlock, &kvb, sizeof(kvb), 0)) {
if (va_space_rw(vs, KdVersionBlock, &kvb, sizeof(kvb), 0)) {
eprintf("Failed to extract KdVersionBlock\n");
return false;
return 1;
}
h = (WinDumpHeader64) {
@@ -330,16 +333,11 @@ static bool fill_header(WinDumpHeader64 *hdr, struct pa_space *ps,
*hdr = h;
return true;
return 0;
}
/*
* fill_context() continues even if it fails to fill contexts of some CPUs.
* A dump may still contain valuable information even if it lacks contexts of
* some CPUs due to dump corruption or a failure before starting CPUs.
*/
static void fill_context(KDDEBUGGER_DATA64 *kdbg,
struct va_space *vs, QEMU_Elf *qe)
static int fill_context(KDDEBUGGER_DATA64 *kdbg,
struct va_space *vs, QEMU_Elf *qe)
{
int i;
@@ -349,10 +347,10 @@ static void fill_context(KDDEBUGGER_DATA64 *kdbg,
WinContext64 ctx;
QEMUCPUState *s = qe->state[i];
if (!va_space_rw(vs, kdbg->KiProcessorBlock + sizeof(Prcb) * i,
&Prcb, sizeof(Prcb), 0)) {
if (va_space_rw(vs, kdbg->KiProcessorBlock + sizeof(Prcb) * i,
&Prcb, sizeof(Prcb), 0)) {
eprintf("Failed to read CPU #%d PRCB location\n", i);
continue;
return 1;
}
if (!Prcb) {
@@ -360,24 +358,26 @@ static void fill_context(KDDEBUGGER_DATA64 *kdbg,
continue;
}
if (!va_space_rw(vs, Prcb + kdbg->OffsetPrcbContext,
&Context, sizeof(Context), 0)) {
if (va_space_rw(vs, Prcb + kdbg->OffsetPrcbContext,
&Context, sizeof(Context), 0)) {
eprintf("Failed to read CPU #%d ContextFrame location\n", i);
continue;
return 1;
}
printf("Filling context for CPU #%d...\n", i);
win_context_init_from_qemu_cpu_state(&ctx, s);
if (!va_space_rw(vs, Context, &ctx, sizeof(ctx), 1)) {
if (va_space_rw(vs, Context, &ctx, sizeof(ctx), 1)) {
eprintf("Failed to fill CPU #%d context\n", i);
continue;
return 1;
}
}
return 0;
}
static bool pe_get_data_dir_entry(uint64_t base, void *start_addr, int idx,
void *entry, size_t size, struct va_space *vs)
static int pe_get_data_dir_entry(uint64_t base, void *start_addr, int idx,
void *entry, size_t size, struct va_space *vs)
{
const char e_magic[2] = "MZ";
const char Signature[4] = "PE\0\0";
@@ -390,38 +390,40 @@ static bool pe_get_data_dir_entry(uint64_t base, void *start_addr, int idx,
QEMU_BUILD_BUG_ON(sizeof(*dos_hdr) >= ELF2DMP_PAGE_SIZE);
if (memcmp(&dos_hdr->e_magic, e_magic, sizeof(e_magic))) {
return false;
return 1;
}
if (!va_space_rw(vs, base + dos_hdr->e_lfanew,
&nt_hdrs, sizeof(nt_hdrs), 0)) {
return false;
if (va_space_rw(vs, base + dos_hdr->e_lfanew,
&nt_hdrs, sizeof(nt_hdrs), 0)) {
return 1;
}
if (memcmp(&nt_hdrs.Signature, Signature, sizeof(Signature)) ||
file_hdr->Machine != 0x8664 || opt_hdr->Magic != 0x020b) {
return false;
return 1;
}
if (!va_space_rw(vs, base + data_dir[idx].VirtualAddress, entry, size, 0)) {
return false;
if (va_space_rw(vs,
base + data_dir[idx].VirtualAddress,
entry, size, 0)) {
return 1;
}
printf("Data directory entry #%d: RVA = 0x%08"PRIx32"\n", idx,
(uint32_t)data_dir[idx].VirtualAddress);
return true;
return 0;
}
static bool write_dump(struct pa_space *ps,
WinDumpHeader64 *hdr, const char *name)
static int write_dump(struct pa_space *ps,
WinDumpHeader64 *hdr, const char *name)
{
FILE *dmp_file = fopen(name, "wb");
size_t i;
if (!dmp_file) {
eprintf("Failed to open output file \'%s\'\n", name);
return false;
return 1;
}
printf("Writing header to file...\n");
@@ -429,7 +431,7 @@ static bool write_dump(struct pa_space *ps,
if (fwrite(hdr, sizeof(*hdr), 1, dmp_file) != 1) {
eprintf("Failed to write dump header\n");
fclose(dmp_file);
return false;
return 1;
}
for (i = 0; i < ps->block_nr; i++) {
@@ -440,11 +442,11 @@ static bool write_dump(struct pa_space *ps,
if (fwrite(b->addr, b->size, 1, dmp_file) != 1) {
eprintf("Failed to write block\n");
fclose(dmp_file);
return false;
return 1;
}
}
return !fclose(dmp_file);
return fclose(dmp_file);
}
static bool pe_check_pdb_name(uint64_t base, void *start_addr,
@@ -454,8 +456,8 @@ static bool pe_check_pdb_name(uint64_t base, void *start_addr,
IMAGE_DEBUG_DIRECTORY debug_dir;
char pdb_name[sizeof(PDB_NAME)];
if (!pe_get_data_dir_entry(base, start_addr, IMAGE_FILE_DEBUG_DIRECTORY,
&debug_dir, sizeof(debug_dir), vs)) {
if (pe_get_data_dir_entry(base, start_addr, IMAGE_FILE_DEBUG_DIRECTORY,
&debug_dir, sizeof(debug_dir), vs)) {
eprintf("Failed to get Debug Directory\n");
return false;
}
@@ -465,8 +467,9 @@ static bool pe_check_pdb_name(uint64_t base, void *start_addr,
return false;
}
if (!va_space_rw(vs, base + debug_dir.AddressOfRawData,
rsds, sizeof(*rsds), 0)) {
if (va_space_rw(vs,
base + debug_dir.AddressOfRawData,
rsds, sizeof(*rsds), 0)) {
eprintf("Failed to resolve OMFSignatureRSDS\n");
return false;
}
@@ -482,9 +485,9 @@ static bool pe_check_pdb_name(uint64_t base, void *start_addr,
return false;
}
if (!va_space_rw(vs, base + debug_dir.AddressOfRawData +
offsetof(OMFSignatureRSDS, name),
pdb_name, sizeof(PDB_NAME), 0)) {
if (va_space_rw(vs, base + debug_dir.AddressOfRawData +
offsetof(OMFSignatureRSDS, name), pdb_name, sizeof(PDB_NAME),
0)) {
eprintf("Failed to resolve PDB name\n");
return false;
}
@@ -508,7 +511,7 @@ static void pe_get_pdb_symstore_hash(OMFSignatureRSDS *rsds, char *hash)
int main(int argc, char *argv[])
{
int err = 1;
int err = 0;
QEMU_Elf qemu_elf;
struct pa_space ps;
struct va_space vs;
@@ -532,27 +535,33 @@ int main(int argc, char *argv[])
return 1;
}
if (!QEMU_Elf_init(&qemu_elf, argv[1])) {
if (QEMU_Elf_init(&qemu_elf, argv[1])) {
eprintf("Failed to initialize QEMU ELF dump\n");
return 1;
}
pa_space_create(&ps, &qemu_elf);
if (pa_space_create(&ps, &qemu_elf)) {
eprintf("Failed to initialize physical address space\n");
err = 1;
goto out_elf;
}
state = qemu_elf.state[0];
printf("CPU #0 CR3 is 0x%016"PRIx64"\n", state->cr[3]);
va_space_create(&vs, &ps, state->cr[3]);
if (!fix_dtb(&vs, &qemu_elf)) {
if (fix_dtb(&vs, &qemu_elf)) {
eprintf("Failed to find paging base\n");
goto out_ps;
err = 1;
goto out_elf;
}
printf("CPU #0 IDT is at 0x%016"PRIx64"\n", state->idt.base);
if (!va_space_rw(&vs, state->idt.base,
&first_idt_desc, sizeof(first_idt_desc), 0)) {
if (va_space_rw(&vs, state->idt.base,
&first_idt_desc, sizeof(first_idt_desc), 0)) {
eprintf("Failed to get CPU #0 IDT[0]\n");
err = 1;
goto out_ps;
}
printf("CPU #0 IDT[0] -> 0x%016"PRIx64"\n", idt_desc_addr(first_idt_desc));
@@ -577,6 +586,7 @@ int main(int argc, char *argv[])
if (!kernel_found) {
eprintf("Failed to find NT kernel image\n");
err = 1;
goto out_ps;
}
@@ -588,40 +598,47 @@ int main(int argc, char *argv[])
sprintf(pdb_url, "%s%s/%s/%s", SYM_URL_BASE, PDB_NAME, pdb_hash, PDB_NAME);
printf("PDB URL is %s\n", pdb_url);
if (!download_url(PDB_NAME, pdb_url)) {
if (download_url(PDB_NAME, pdb_url)) {
eprintf("Failed to download PDB file\n");
err = 1;
goto out_ps;
}
if (!pdb_init_from_file(PDB_NAME, &pdb)) {
if (pdb_init_from_file(PDB_NAME, &pdb)) {
eprintf("Failed to initialize PDB reader\n");
err = 1;
goto out_pdb_file;
}
if (!SYM_RESOLVE(KernBase, &pdb, KdDebuggerDataBlock) ||
!SYM_RESOLVE(KernBase, &pdb, KdVersionBlock)) {
err = 1;
goto out_pdb;
}
kdbg = get_kdbg(KernBase, &pdb, &vs, KdDebuggerDataBlock);
if (!kdbg) {
err = 1;
goto out_pdb;
}
if (!fill_header(&header, &ps, &vs, KdDebuggerDataBlock, kdbg,
KdVersionBlock, qemu_elf.state_nr)) {
if (fill_header(&header, &ps, &vs, KdDebuggerDataBlock, kdbg,
KdVersionBlock, qemu_elf.state_nr)) {
err = 1;
goto out_kdbg;
}
fill_context(kdbg, &vs, &qemu_elf);
if (fill_context(kdbg, &vs, &qemu_elf)) {
err = 1;
goto out_kdbg;
}
if (!write_dump(&ps, &header, argv[2])) {
if (write_dump(&ps, &header, argv[2])) {
eprintf("Failed to save dump\n");
err = 1;
goto out_kdbg;
}
err = 0;
out_kdbg:
g_free(kdbg);
out_pdb:
@@ -630,6 +647,7 @@ out_pdb_file:
unlink(PDB_NAME);
out_ps:
pa_space_destroy(&ps);
out_elf:
QEMU_Elf_exit(&qemu_elf);
return err;
+34 -27
View File
@@ -19,7 +19,6 @@
*/
#include "qemu/osdep.h"
#include "qemu/bswap.h"
#include "pdb.h"
#include "err.h"
@@ -159,35 +158,36 @@ static void *pdb_ds_read_file(struct pdb_reader* r, uint32_t file_number)
return pdb_ds_read(r->ds.header, block_list, file_size[file_number]);
}
static bool pdb_init_segments(struct pdb_reader *r)
static int pdb_init_segments(struct pdb_reader *r)
{
unsigned stream_idx = r->segments;
r->segs = pdb_ds_read_file(r, stream_idx);
if (!r->segs) {
return false;
return 1;
}
r->segs_size = pdb_get_file_size(r, stream_idx);
if (!r->segs_size) {
return false;
return 1;
}
return true;
return 0;
}
static bool pdb_init_symbols(struct pdb_reader *r)
static int pdb_init_symbols(struct pdb_reader *r)
{
int err = 0;
PDB_SYMBOLS *symbols;
symbols = pdb_ds_read_file(r, 3);
if (!symbols) {
return false;
return 1;
}
r->symbols = symbols;
r->segments = lduw_le_p((const char *)symbols + sizeof(PDB_SYMBOLS) +
r->segments = *(uint16_t *)((const char *)symbols + sizeof(PDB_SYMBOLS) +
symbols->module_size + symbols->offset_size +
symbols->hash_size + symbols->srcmodule_size +
symbols->pdbimport_size + symbols->unknown2_size +
@@ -196,21 +196,22 @@ static bool pdb_init_symbols(struct pdb_reader *r)
/* Read global symbol table */
r->modimage = pdb_ds_read_file(r, symbols->gsym_file);
if (!r->modimage) {
err = 1;
goto out_symbols;
}
return true;
return 0;
out_symbols:
g_free(symbols);
return false;
return err;
}
static bool pdb_reader_ds_init(struct pdb_reader *r, PDB_DS_HEADER *hdr)
static int pdb_reader_ds_init(struct pdb_reader *r, PDB_DS_HEADER *hdr)
{
if (hdr->block_size == 0) {
return false;
return 1;
}
memset(r->file_used, 0, sizeof(r->file_used));
@@ -219,38 +220,42 @@ static bool pdb_reader_ds_init(struct pdb_reader *r, PDB_DS_HEADER *hdr)
hdr->toc_page * hdr->block_size), hdr->toc_size);
if (!r->ds.toc) {
return false;
return 1;
}
return true;
return 0;
}
static bool pdb_reader_init(struct pdb_reader *r, void *data)
static int pdb_reader_init(struct pdb_reader *r, void *data)
{
int err = 0;
const char pdb7[] = "Microsoft C/C++ MSF 7.00";
if (memcmp(data, pdb7, sizeof(pdb7) - 1)) {
return false;
return 1;
}
if (!pdb_reader_ds_init(r, data)) {
return false;
if (pdb_reader_ds_init(r, data)) {
return 1;
}
r->ds.root = pdb_ds_read_file(r, 1);
if (!r->ds.root) {
err = 1;
goto out_ds;
}
if (!pdb_init_symbols(r)) {
if (pdb_init_symbols(r)) {
err = 1;
goto out_root;
}
if (!pdb_init_segments(r)) {
if (pdb_init_segments(r)) {
err = 1;
goto out_sym;
}
return true;
return 0;
out_sym:
pdb_exit_symbols(r);
@@ -259,7 +264,7 @@ out_root:
out_ds:
pdb_reader_ds_exit(r);
return false;
return err;
}
static void pdb_reader_exit(struct pdb_reader *r)
@@ -270,30 +275,32 @@ static void pdb_reader_exit(struct pdb_reader *r)
pdb_reader_ds_exit(r);
}
bool pdb_init_from_file(const char *name, struct pdb_reader *reader)
int pdb_init_from_file(const char *name, struct pdb_reader *reader)
{
GError *gerr = NULL;
int err = 0;
void *map;
reader->gmf = g_mapped_file_new(name, TRUE, &gerr);
if (gerr) {
eprintf("Failed to map PDB file \'%s\'\n", name);
g_error_free(gerr);
return false;
return 1;
}
reader->file_size = g_mapped_file_get_length(reader->gmf);
map = g_mapped_file_get_contents(reader->gmf);
if (!pdb_reader_init(reader, map)) {
if (pdb_reader_init(reader, map)) {
err = 1;
goto out_unmap;
}
return true;
return 0;
out_unmap:
g_mapped_file_unref(reader->gmf);
return false;
return err;
}
void pdb_exit(struct pdb_reader *reader)
+1 -1
View File
@@ -233,7 +233,7 @@ struct pdb_reader {
size_t segs_size;
};
bool pdb_init_from_file(const char *name, struct pdb_reader *reader);
int pdb_init_from_file(const char *name, struct pdb_reader *reader);
void pdb_exit(struct pdb_reader *reader);
uint64_t pdb_resolve(uint64_t img_base, struct pdb_reader *r, const char *name);
uint64_t pdb_find_public_v3_symbol(struct pdb_reader *reader, const char *name);
+64 -86
View File
@@ -6,7 +6,6 @@
*/
#include "qemu/osdep.h"
#include "qemu/host-utils.h"
#include "err.h"
#include "qemu_elf.h"
@@ -16,11 +15,36 @@
#define ROUND_UP(n, d) (((n) + (d) - 1) & -(0 ? (n) : (d)))
#endif
#ifndef DIV_ROUND_UP
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
#endif
#define ELF_NOTE_SIZE(hdr_size, name_size, desc_size) \
((DIV_ROUND_UP((hdr_size), 4) + \
DIV_ROUND_UP((name_size), 4) + \
DIV_ROUND_UP((desc_size), 4)) * 4)
int is_system(QEMUCPUState *s)
{
return s->gs.base >> 63;
}
static char *nhdr_get_name(Elf64_Nhdr *nhdr)
{
return (char *)nhdr + ROUND_UP(sizeof(*nhdr), 4);
}
static void *nhdr_get_desc(Elf64_Nhdr *nhdr)
{
return nhdr_get_name(nhdr) + ROUND_UP(nhdr->n_namesz, 4);
}
static Elf64_Nhdr *nhdr_get_next(Elf64_Nhdr *nhdr)
{
return (void *)((uint8_t *)nhdr + ELF_NOTE_SIZE(sizeof(*nhdr),
nhdr->n_namesz, nhdr->n_descsz));
}
Elf64_Phdr *elf64_getphdr(void *map)
{
Elf64_Ehdr *ehdr = map;
@@ -36,92 +60,54 @@ Elf64_Half elf_getphdrnum(void *map)
return ehdr->e_phnum;
}
static bool advance_note_offset(uint64_t *offsetp, uint64_t size, uint64_t end)
{
uint64_t offset = *offsetp;
if (uadd64_overflow(offset, size, &offset) || offset > UINT64_MAX - 3) {
return false;
}
offset = ROUND_UP(offset, 4);
if (offset > end) {
return false;
}
*offsetp = offset;
return true;
}
static bool init_states(QEMU_Elf *qe)
static int init_states(QEMU_Elf *qe)
{
Elf64_Phdr *phdr = elf64_getphdr(qe->map);
Elf64_Nhdr *start = (void *)((uint8_t *)qe->map + phdr[0].p_offset);
Elf64_Nhdr *end = (void *)((uint8_t *)start + phdr[0].p_memsz);
Elf64_Nhdr *nhdr;
GPtrArray *states;
QEMUCPUState *state;
uint32_t state_size;
uint64_t offset;
uint64_t end_offset;
char *name;
size_t cpu_nr = 0;
if (phdr[0].p_type != PT_NOTE) {
eprintf("Failed to find PT_NOTE\n");
return false;
return 1;
}
qe->has_kernel_gs_base = 1;
offset = phdr[0].p_offset;
states = g_ptr_array_new();
if (uadd64_overflow(offset, phdr[0].p_memsz, &end_offset) ||
end_offset > qe->size) {
end_offset = qe->size;
}
for (nhdr = start; nhdr < end; nhdr = nhdr_get_next(nhdr)) {
if (!strcmp(nhdr_get_name(nhdr), QEMU_NOTE_NAME)) {
QEMUCPUState *state = nhdr_get_desc(nhdr);
while (offset < end_offset) {
nhdr = (void *)((uint8_t *)qe->map + offset);
if (!advance_note_offset(&offset, sizeof(*nhdr), end_offset)) {
break;
}
name = (char *)qe->map + offset;
if (!advance_note_offset(&offset, nhdr->n_namesz, end_offset)) {
break;
}
state = (void *)((uint8_t *)qe->map + offset);
if (!advance_note_offset(&offset, nhdr->n_descsz, end_offset)) {
break;
}
if (!strcmp(name, QEMU_NOTE_NAME) &&
nhdr->n_descsz >= offsetof(QEMUCPUState, kernel_gs_base)) {
state_size = MIN(state->size, nhdr->n_descsz);
if (state_size < sizeof(*state)) {
eprintf("CPU #%u: QEMU CPU state size %u doesn't match\n",
states->len, state_size);
if (state->size < sizeof(*state)) {
eprintf("CPU #%zu: QEMU CPU state size %u doesn't match\n",
cpu_nr, state->size);
/*
* We assume either every QEMU CPU state has KERNEL_GS_BASE or
* no one has.
*/
qe->has_kernel_gs_base = 0;
}
g_ptr_array_add(states, state);
cpu_nr++;
}
}
printf("%u CPU states has been found\n", states->len);
printf("%zu CPU states has been found\n", cpu_nr);
qe->state_nr = states->len;
qe->state = (void *)g_ptr_array_free(states, FALSE);
qe->state = g_new(QEMUCPUState*, cpu_nr);
return true;
cpu_nr = 0;
for (nhdr = start; nhdr < end; nhdr = nhdr_get_next(nhdr)) {
if (!strcmp(nhdr_get_name(nhdr), QEMU_NOTE_NAME)) {
qe->state[cpu_nr] = nhdr_get_desc(nhdr);
cpu_nr++;
}
}
qe->state_nr = cpu_nr;
return 0;
}
static void exit_states(QEMU_Elf *qe)
@@ -132,7 +118,6 @@ static void exit_states(QEMU_Elf *qe)
static bool check_ehdr(QEMU_Elf *qe)
{
Elf64_Ehdr *ehdr = qe->map;
uint64_t phendoff;
if (sizeof(Elf64_Ehdr) > qe->size) {
eprintf("Invalid input dump file size\n");
@@ -174,17 +159,10 @@ static bool check_ehdr(QEMU_Elf *qe)
return false;
}
if (umul64_overflow(ehdr->e_phnum, sizeof(Elf64_Phdr), &phendoff) ||
uadd64_overflow(phendoff, ehdr->e_phoff, &phendoff) ||
phendoff > qe->size) {
eprintf("phdrs do not fit in file\n");
return false;
}
return true;
}
static bool QEMU_Elf_map(QEMU_Elf *qe, const char *filename)
static int QEMU_Elf_map(QEMU_Elf *qe, const char *filename)
{
#ifdef CONFIG_LINUX
struct stat st;
@@ -195,13 +173,13 @@ static bool QEMU_Elf_map(QEMU_Elf *qe, const char *filename)
fd = open(filename, O_RDONLY, 0);
if (fd == -1) {
eprintf("Failed to open ELF dump file \'%s\'\n", filename);
return false;
return 1;
}
if (fstat(fd, &st)) {
eprintf("Failed to get size of ELF dump file\n");
close(fd);
return false;
return 1;
}
qe->size = st.st_size;
@@ -210,7 +188,7 @@ static bool QEMU_Elf_map(QEMU_Elf *qe, const char *filename)
if (qe->map == MAP_FAILED) {
eprintf("Failed to map ELF file\n");
close(fd);
return false;
return 1;
}
close(fd);
@@ -223,14 +201,14 @@ static bool QEMU_Elf_map(QEMU_Elf *qe, const char *filename)
if (gerr) {
eprintf("Failed to map ELF dump file \'%s\'\n", filename);
g_error_free(gerr);
return false;
return 1;
}
qe->map = g_mapped_file_get_contents(qe->gmf);
qe->size = g_mapped_file_get_length(qe->gmf);
#endif
return true;
return 0;
}
static void QEMU_Elf_unmap(QEMU_Elf *qe)
@@ -242,25 +220,25 @@ static void QEMU_Elf_unmap(QEMU_Elf *qe)
#endif
}
bool QEMU_Elf_init(QEMU_Elf *qe, const char *filename)
int QEMU_Elf_init(QEMU_Elf *qe, const char *filename)
{
if (!QEMU_Elf_map(qe, filename)) {
return false;
if (QEMU_Elf_map(qe, filename)) {
return 1;
}
if (!check_ehdr(qe)) {
eprintf("Input file has the wrong format\n");
QEMU_Elf_unmap(qe);
return false;
return 1;
}
if (!init_states(qe)) {
if (init_states(qe)) {
eprintf("Failed to extract QEMU CPU states\n");
QEMU_Elf_unmap(qe);
return false;
return 1;
}
return true;
return 0;
}
void QEMU_Elf_exit(QEMU_Elf *qe)
+1 -1
View File
@@ -42,7 +42,7 @@ typedef struct QEMU_Elf {
int has_kernel_gs_base;
} QEMU_Elf;
bool QEMU_Elf_init(QEMU_Elf *qe, const char *filename);
int QEMU_Elf_init(QEMU_Elf *qe, const char *filename);
void QEMU_Elf_exit(QEMU_Elf *qe);
Elf64_Phdr *elf64_getphdr(void *map);
+3 -21
View File
@@ -311,24 +311,6 @@ static Register *init_vcpu_register(qemu_plugin_reg_descriptor *desc)
return reg;
}
/*
* g_pattern_match_string has been deprecated in Glib since 2.70 and
* will complain about it if you try to use it. Fortunately the
* signature of both functions is the same making it easy to work
* around.
*/
static inline
gboolean g_pattern_spec_match_string_qemu(GPatternSpec *pspec,
const gchar *string)
{
#if GLIB_CHECK_VERSION(2, 70, 0)
return g_pattern_spec_match_string(pspec, string);
#else
return g_pattern_match_string(pspec, string);
#endif
};
#define g_pattern_spec_match_string(p, s) g_pattern_spec_match_string_qemu(p, s)
static GPtrArray *registers_init(int vcpu_index)
{
g_autoptr(GPtrArray) registers = g_ptr_array_new();
@@ -345,8 +327,8 @@ static GPtrArray *registers_init(int vcpu_index)
for (int p = 0; p < rmatches->len; p++) {
g_autoptr(GPatternSpec) pat = g_pattern_spec_new(rmatches->pdata[p]);
g_autofree gchar *rd_lower = g_utf8_strdown(rd->name, -1);
if (g_pattern_spec_match_string(pat, rd->name) ||
g_pattern_spec_match_string(pat, rd_lower)) {
if (g_pattern_match_string(pat, rd->name) ||
g_pattern_match_string(pat, rd_lower)) {
Register *reg = init_vcpu_register(rd);
g_ptr_array_add(registers, reg);
@@ -354,7 +336,7 @@ static GPtrArray *registers_init(int vcpu_index)
if (disas_assist) {
g_mutex_lock(&add_reg_name_lock);
if (!g_ptr_array_find(all_reg_names, reg->name, NULL)) {
g_ptr_array_add(all_reg_names, (gpointer)reg->name);
g_ptr_array_add(all_reg_names, reg->name);
}
g_mutex_unlock(&add_reg_name_lock);
}
+20 -30
View File
@@ -34,8 +34,8 @@ static guint64 limit = 20;
*/
typedef struct {
uint64_t start_addr;
struct qemu_plugin_scoreboard *exec_count;
int trans_count;
uint64_t exec_count;
int trans_count;
unsigned long insns;
} ExecCount;
@@ -43,17 +43,7 @@ static gint cmp_exec_count(gconstpointer a, gconstpointer b)
{
ExecCount *ea = (ExecCount *) a;
ExecCount *eb = (ExecCount *) b;
uint64_t count_a =
qemu_plugin_u64_sum(qemu_plugin_scoreboard_u64(ea->exec_count));
uint64_t count_b =
qemu_plugin_u64_sum(qemu_plugin_scoreboard_u64(eb->exec_count));
return count_a > count_b ? -1 : 1;
}
static void exec_count_free(gpointer key, gpointer value, gpointer user_data)
{
ExecCount *cnt = value;
qemu_plugin_scoreboard_free(cnt->exec_count);
return ea->exec_count > eb->exec_count ? -1 : 1;
}
static void plugin_exit(qemu_plugin_id_t id, void *p)
@@ -62,6 +52,7 @@ static void plugin_exit(qemu_plugin_id_t id, void *p)
GList *counts, *it;
int i;
g_mutex_lock(&lock);
g_string_append_printf(report, "%d entries in the hash table\n",
g_hash_table_size(hotblocks));
counts = g_hash_table_get_values(hotblocks);
@@ -72,21 +63,16 @@ static void plugin_exit(qemu_plugin_id_t id, void *p)
for (i = 0; i < limit && it->next; i++, it = it->next) {
ExecCount *rec = (ExecCount *) it->data;
g_string_append_printf(
report, "0x%016"PRIx64", %d, %ld, %"PRId64"\n",
rec->start_addr, rec->trans_count,
rec->insns,
qemu_plugin_u64_sum(
qemu_plugin_scoreboard_u64(rec->exec_count)));
g_string_append_printf(report, "0x%016"PRIx64", %d, %ld, %"PRId64"\n",
rec->start_addr, rec->trans_count,
rec->insns, rec->exec_count);
}
g_list_free(it);
}
g_mutex_unlock(&lock);
qemu_plugin_outs(report->str);
g_hash_table_foreach(hotblocks, exec_count_free, NULL);
g_hash_table_destroy(hotblocks);
}
static void plugin_init(void)
@@ -96,9 +82,15 @@ static void plugin_init(void)
static void vcpu_tb_exec(unsigned int cpu_index, void *udata)
{
ExecCount *cnt = (ExecCount *)udata;
qemu_plugin_u64_add(qemu_plugin_scoreboard_u64(cnt->exec_count),
cpu_index, 1);
ExecCount *cnt;
uint64_t hash = (uint64_t) udata;
g_mutex_lock(&lock);
cnt = (ExecCount *) g_hash_table_lookup(hotblocks, (gconstpointer) hash);
/* should always succeed */
g_assert(cnt);
cnt->exec_count++;
g_mutex_unlock(&lock);
}
/*
@@ -122,20 +114,18 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
cnt->start_addr = pc;
cnt->trans_count = 1;
cnt->insns = insns;
cnt->exec_count = qemu_plugin_scoreboard_new(sizeof(uint64_t));
g_hash_table_insert(hotblocks, (gpointer) hash, (gpointer) cnt);
}
g_mutex_unlock(&lock);
if (do_inline) {
qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu(
tb, QEMU_PLUGIN_INLINE_ADD_U64,
qemu_plugin_scoreboard_u64(cnt->exec_count), 1);
qemu_plugin_register_vcpu_tb_exec_inline(tb, QEMU_PLUGIN_INLINE_ADD_U64,
&cnt->exec_count, 1);
} else {
qemu_plugin_register_vcpu_tb_exec_cb(tb, vcpu_tb_exec,
QEMU_PLUGIN_CB_NO_REGS,
(void *)cnt);
(void *)hash);
}
}
+15 -38
View File
@@ -43,13 +43,13 @@ typedef struct {
uint32_t mask;
uint32_t pattern;
CountType what;
qemu_plugin_u64 count;
uint64_t count;
} InsnClassExecCount;
typedef struct {
char *insn;
uint32_t opcode;
qemu_plugin_u64 count;
uint64_t count;
InsnClassExecCount *class;
} InsnExecCount;
@@ -159,15 +159,12 @@ static gint cmp_exec_count(gconstpointer a, gconstpointer b)
{
InsnExecCount *ea = (InsnExecCount *) a;
InsnExecCount *eb = (InsnExecCount *) b;
uint64_t count_a = qemu_plugin_u64_sum(ea->count);
uint64_t count_b = qemu_plugin_u64_sum(eb->count);
return count_a > count_b ? -1 : 1;
return ea->count > eb->count ? -1 : 1;
}
static void free_record(gpointer data)
{
InsnExecCount *rec = (InsnExecCount *) data;
qemu_plugin_scoreboard_free(rec->count.score);
g_free(rec->insn);
g_free(rec);
}
@@ -176,7 +173,6 @@ static void plugin_exit(qemu_plugin_id_t id, void *p)
{
g_autoptr(GString) report = g_string_new("Instruction Classes:\n");
int i;
uint64_t total_count;
GList *counts;
InsnClassExecCount *class = NULL;
@@ -184,12 +180,11 @@ static void plugin_exit(qemu_plugin_id_t id, void *p)
class = &class_table[i];
switch (class->what) {
case COUNT_CLASS:
total_count = qemu_plugin_u64_sum(class->count);
if (total_count || verbose) {
if (class->count || verbose) {
g_string_append_printf(report,
"Class: %-24s\t(%" PRId64 " hits)\n",
class->class,
total_count);
class->count);
}
break;
case COUNT_INDIVIDUAL:
@@ -217,7 +212,7 @@ static void plugin_exit(qemu_plugin_id_t id, void *p)
"Instr: %-24s\t(%" PRId64 " hits)"
"\t(op=0x%08x/%s)\n",
rec->insn,
qemu_plugin_u64_sum(rec->count),
rec->count,
rec->opcode,
rec->class ?
rec->class->class : "un-categorised");
@@ -226,12 +221,6 @@ static void plugin_exit(qemu_plugin_id_t id, void *p)
}
g_hash_table_destroy(insns);
for (i = 0; i < ARRAY_SIZE(class_tables); i++) {
for (int j = 0; j < class_tables[i].table_sz; ++j) {
qemu_plugin_scoreboard_free(class_tables[i].table[j].count.score);
}
}
qemu_plugin_outs(report->str);
}
@@ -243,12 +232,11 @@ static void plugin_init(void)
static void vcpu_insn_exec_before(unsigned int cpu_index, void *udata)
{
struct qemu_plugin_scoreboard *score = udata;
qemu_plugin_u64_add(qemu_plugin_scoreboard_u64(score), cpu_index, 1);
uint64_t *count = (uint64_t *) udata;
(*count)++;
}
static struct qemu_plugin_scoreboard *find_counter(
struct qemu_plugin_insn *insn)
static uint64_t *find_counter(struct qemu_plugin_insn *insn)
{
int i;
uint64_t *cnt = NULL;
@@ -277,7 +265,7 @@ static struct qemu_plugin_scoreboard *find_counter(
case COUNT_NONE:
return NULL;
case COUNT_CLASS:
return class->count.score;
return &class->count;
case COUNT_INDIVIDUAL:
{
InsnExecCount *icount;
@@ -291,16 +279,13 @@ static struct qemu_plugin_scoreboard *find_counter(
icount->opcode = opcode;
icount->insn = qemu_plugin_insn_disas(insn);
icount->class = class;
struct qemu_plugin_scoreboard *score =
qemu_plugin_scoreboard_new(sizeof(uint64_t));
icount->count = qemu_plugin_scoreboard_u64(score);
g_hash_table_insert(insns, GUINT_TO_POINTER(opcode),
(gpointer) icount);
}
g_mutex_unlock(&lock);
return icount->count.score;
return &icount->count;
}
default:
g_assert_not_reached();
@@ -315,14 +300,14 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
size_t i;
for (i = 0; i < n; i++) {
uint64_t *cnt;
struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
struct qemu_plugin_scoreboard *cnt = find_counter(insn);
cnt = find_counter(insn);
if (cnt) {
if (do_inline) {
qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(
insn, QEMU_PLUGIN_INLINE_ADD_U64,
qemu_plugin_scoreboard_u64(cnt), 1);
qemu_plugin_register_vcpu_insn_exec_inline(
insn, QEMU_PLUGIN_INLINE_ADD_U64, cnt, 1);
} else {
qemu_plugin_register_vcpu_insn_exec_cb(
insn, vcpu_insn_exec_before, QEMU_PLUGIN_CB_NO_REGS, cnt);
@@ -337,14 +322,6 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
{
int i;
for (i = 0; i < ARRAY_SIZE(class_tables); i++) {
for (int j = 0; j < class_tables[i].table_sz; ++j) {
struct qemu_plugin_scoreboard *score =
qemu_plugin_scoreboard_new(sizeof(uint64_t));
class_tables[i].table[j].count = qemu_plugin_scoreboard_u64(score);
}
}
/* Select a class table appropriate to the guest architecture */
for (i = 0; i < ARRAY_SIZE(class_tables); i++) {
ClassSelector *entry = &class_tables[i];
-25
View File
@@ -100,31 +100,6 @@ static void plugin_exit(qemu_plugin_id_t id, void *p)
plugin_cleanup(id);
}
/*
* g_memdup has been deprecated in Glib since 2.68 and
* will complain about it if you try to use it. However until
* glib_req_ver for QEMU is bumped we make a copy of the glib-compat
* handler.
*/
static inline gpointer g_memdup2_qemu(gconstpointer mem, gsize byte_size)
{
#if GLIB_CHECK_VERSION(2, 68, 0)
return g_memdup2(mem, byte_size);
#else
gpointer new_mem;
if (mem && byte_size != 0) {
new_mem = g_malloc(byte_size);
memcpy(new_mem, mem, byte_size);
} else {
new_mem = NULL;
}
return new_mem;
#endif
}
#define g_memdup2(m, s) g_memdup2_qemu(m, s)
static void report_divergance(ExecState *us, ExecState *them)
{
DivergeState divrec = { log, 0 };
+56 -65
View File
@@ -20,56 +20,6 @@
#include <gcrypt.h>
static int qcrypto_cipher_alg_to_gcry_alg(QCryptoCipherAlgorithm alg)
{
switch (alg) {
case QCRYPTO_CIPHER_ALG_DES:
return GCRY_CIPHER_DES;
case QCRYPTO_CIPHER_ALG_3DES:
return GCRY_CIPHER_3DES;
case QCRYPTO_CIPHER_ALG_AES_128:
return GCRY_CIPHER_AES128;
case QCRYPTO_CIPHER_ALG_AES_192:
return GCRY_CIPHER_AES192;
case QCRYPTO_CIPHER_ALG_AES_256:
return GCRY_CIPHER_AES256;
case QCRYPTO_CIPHER_ALG_CAST5_128:
return GCRY_CIPHER_CAST5;
case QCRYPTO_CIPHER_ALG_SERPENT_128:
return GCRY_CIPHER_SERPENT128;
case QCRYPTO_CIPHER_ALG_SERPENT_192:
return GCRY_CIPHER_SERPENT192;
case QCRYPTO_CIPHER_ALG_SERPENT_256:
return GCRY_CIPHER_SERPENT256;
case QCRYPTO_CIPHER_ALG_TWOFISH_128:
return GCRY_CIPHER_TWOFISH128;
case QCRYPTO_CIPHER_ALG_TWOFISH_256:
return GCRY_CIPHER_TWOFISH;
#ifdef CONFIG_CRYPTO_SM4
case QCRYPTO_CIPHER_ALG_SM4:
return GCRY_CIPHER_SM4;
#endif
default:
return GCRY_CIPHER_NONE;
}
}
static int qcrypto_cipher_mode_to_gcry_mode(QCryptoCipherMode mode)
{
switch (mode) {
case QCRYPTO_CIPHER_MODE_ECB:
return GCRY_CIPHER_MODE_ECB;
case QCRYPTO_CIPHER_MODE_XTS:
return GCRY_CIPHER_MODE_XTS;
case QCRYPTO_CIPHER_MODE_CBC:
return GCRY_CIPHER_MODE_CBC;
case QCRYPTO_CIPHER_MODE_CTR:
return GCRY_CIPHER_MODE_CTR;
default:
return GCRY_CIPHER_MODE_NONE;
}
}
bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
QCryptoCipherMode mode)
{
@@ -93,11 +43,6 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
return false;
}
if (gcry_cipher_algo_info(qcrypto_cipher_alg_to_gcry_alg(alg),
GCRYCTL_TEST_ALGO, NULL, NULL) != 0) {
return false;
}
switch (mode) {
case QCRYPTO_CIPHER_MODE_ECB:
case QCRYPTO_CIPHER_MODE_CBC:
@@ -243,26 +188,72 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
return NULL;
}
gcryalg = qcrypto_cipher_alg_to_gcry_alg(alg);
if (gcryalg == GCRY_CIPHER_NONE) {
switch (alg) {
case QCRYPTO_CIPHER_ALG_DES:
gcryalg = GCRY_CIPHER_DES;
break;
case QCRYPTO_CIPHER_ALG_3DES:
gcryalg = GCRY_CIPHER_3DES;
break;
case QCRYPTO_CIPHER_ALG_AES_128:
gcryalg = GCRY_CIPHER_AES128;
break;
case QCRYPTO_CIPHER_ALG_AES_192:
gcryalg = GCRY_CIPHER_AES192;
break;
case QCRYPTO_CIPHER_ALG_AES_256:
gcryalg = GCRY_CIPHER_AES256;
break;
case QCRYPTO_CIPHER_ALG_CAST5_128:
gcryalg = GCRY_CIPHER_CAST5;
break;
case QCRYPTO_CIPHER_ALG_SERPENT_128:
gcryalg = GCRY_CIPHER_SERPENT128;
break;
case QCRYPTO_CIPHER_ALG_SERPENT_192:
gcryalg = GCRY_CIPHER_SERPENT192;
break;
case QCRYPTO_CIPHER_ALG_SERPENT_256:
gcryalg = GCRY_CIPHER_SERPENT256;
break;
case QCRYPTO_CIPHER_ALG_TWOFISH_128:
gcryalg = GCRY_CIPHER_TWOFISH128;
break;
case QCRYPTO_CIPHER_ALG_TWOFISH_256:
gcryalg = GCRY_CIPHER_TWOFISH;
break;
#ifdef CONFIG_CRYPTO_SM4
case QCRYPTO_CIPHER_ALG_SM4:
gcryalg = GCRY_CIPHER_SM4;
break;
#endif
default:
error_setg(errp, "Unsupported cipher algorithm %s",
QCryptoCipherAlgorithm_str(alg));
return NULL;
}
gcrymode = qcrypto_cipher_mode_to_gcry_mode(mode);
if (gcrymode == GCRY_CIPHER_MODE_NONE) {
drv = &qcrypto_gcrypt_driver;
switch (mode) {
case QCRYPTO_CIPHER_MODE_ECB:
gcrymode = GCRY_CIPHER_MODE_ECB;
break;
case QCRYPTO_CIPHER_MODE_XTS:
gcrymode = GCRY_CIPHER_MODE_XTS;
break;
case QCRYPTO_CIPHER_MODE_CBC:
gcrymode = GCRY_CIPHER_MODE_CBC;
break;
case QCRYPTO_CIPHER_MODE_CTR:
drv = &qcrypto_gcrypt_ctr_driver;
gcrymode = GCRY_CIPHER_MODE_CTR;
break;
default:
error_setg(errp, "Unsupported cipher mode %s",
QCryptoCipherMode_str(mode));
return NULL;
}
if (mode == QCRYPTO_CIPHER_MODE_CTR) {
drv = &qcrypto_gcrypt_ctr_driver;
} else {
drv = &qcrypto_gcrypt_driver;
}
ctx = g_new0(QCryptoCipherGcrypt, 1);
ctx->base.driver = drv;
+2 -5
View File
@@ -734,19 +734,16 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
#ifdef CONFIG_CRYPTO_SM4
case QCRYPTO_CIPHER_ALG_SM4:
{
QCryptoNettleSm4 *ctx;
const QCryptoCipherDriver *drv;
QCryptoNettleSm4 *ctx = g_new0(QCryptoNettleSm4, 1);
switch (mode) {
case QCRYPTO_CIPHER_MODE_ECB:
drv = &qcrypto_nettle_sm4_driver_ecb;
ctx->base.driver = &qcrypto_nettle_sm4_driver_ecb;
break;
default:
goto bad_cipher_mode;
}
ctx = g_new0(QCryptoNettleSm4, 1);
ctx->base.driver = drv;
sm4_set_encrypt_key(&ctx->key[0], key);
sm4_set_decrypt_key(&ctx->key[1], key);
+1 -1
View File
@@ -33,7 +33,7 @@ bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash)
case QCRYPTO_HASH_ALG_SHA384:
case QCRYPTO_HASH_ALG_SHA512:
case QCRYPTO_HASH_ALG_RIPEMD160:
return qcrypto_hash_supports(hash);
return true;
default:
return false;
}
+1 -1
View File
@@ -33,7 +33,7 @@ bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash)
case QCRYPTO_HASH_ALG_SHA384:
case QCRYPTO_HASH_ALG_SHA512:
case QCRYPTO_HASH_ALG_RIPEMD160:
return qcrypto_hash_supports(hash);
return true;
default:
return false;
}
+7 -46
View File
@@ -19,7 +19,6 @@
*/
#include "qemu/osdep.h"
#include "qemu/thread.h"
#include "qapi/error.h"
#include "crypto/pbkdf.h"
#ifndef _WIN32
@@ -86,28 +85,12 @@ static int qcrypto_pbkdf2_get_thread_cpu(unsigned long long *val_ms,
#endif
}
typedef struct CountItersData {
QCryptoHashAlgorithm hash;
const uint8_t *key;
size_t nkey;
const uint8_t *salt;
size_t nsalt;
size_t nout;
uint64_t iterations;
Error **errp;
} CountItersData;
static void *threaded_qcrypto_pbkdf2_count_iters(void *data)
uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
const uint8_t *key, size_t nkey,
const uint8_t *salt, size_t nsalt,
size_t nout,
Error **errp)
{
CountItersData *iters_data = (CountItersData *) data;
QCryptoHashAlgorithm hash = iters_data->hash;
const uint8_t *key = iters_data->key;
size_t nkey = iters_data->nkey;
const uint8_t *salt = iters_data->salt;
size_t nsalt = iters_data->nsalt;
size_t nout = iters_data->nout;
Error **errp = iters_data->errp;
uint64_t ret = -1;
g_autofree uint8_t *out = g_new(uint8_t, nout);
uint64_t iterations = (1 << 15);
@@ -131,10 +114,7 @@ static void *threaded_qcrypto_pbkdf2_count_iters(void *data)
delta_ms = end_ms - start_ms;
if (delta_ms == 0) { /* sanity check */
error_setg(errp, "Unable to get accurate CPU usage");
goto cleanup;
} else if (delta_ms > 500) {
if (delta_ms > 500) {
break;
} else if (delta_ms < 100) {
iterations = iterations * 10;
@@ -149,24 +129,5 @@ static void *threaded_qcrypto_pbkdf2_count_iters(void *data)
cleanup:
memset(out, 0, nout);
iters_data->iterations = ret;
return NULL;
}
uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
const uint8_t *key, size_t nkey,
const uint8_t *salt, size_t nsalt,
size_t nout,
Error **errp)
{
CountItersData data = {
hash, key, nkey, salt, nsalt, nout, 0, errp
};
QemuThread thread;
qemu_thread_create(&thread, "pbkdf2", threaded_qcrypto_pbkdf2_count_iters,
&data, QEMU_THREAD_JOINABLE);
qemu_thread_join(&thread);
return data.iterations;
return ret;
}
-1
View File
@@ -243,7 +243,6 @@ qcrypto_tls_creds_psk_finalize(Object *obj)
QCryptoTLSCredsPSK *creds = QCRYPTO_TLS_CREDS_PSK(obj);
qcrypto_tls_creds_psk_unload(creds);
g_free(creds->username);
}
static void
-1
View File
@@ -34,7 +34,6 @@ void monitor_disas(Monitor *mon, CPUState *cpu, uint64_t pc,
disas_initialize_debug_target(&s, cpu);
s.info.fprintf_func = disas_gstring_printf;
s.info.stream = (FILE *)ds; /* abuse this slot */
s.info.show_opcodes = true;
if (is_physical) {
s.info.read_memory_func = physical_read_memory;
-2
View File
@@ -211,7 +211,6 @@ void target_disas(FILE *out, CPUState *cpu, uint64_t code, size_t size)
s.info.stream = out;
s.info.buffer_vma = code;
s.info.buffer_length = size;
s.info.show_opcodes = true;
if (s.info.cap_arch >= 0 && cap_disas_target(&s.info, code, size)) {
return;
@@ -300,7 +299,6 @@ void disas(FILE *out, const void *code, size_t size)
s.info.buffer = code;
s.info.buffer_vma = (uintptr_t)code;
s.info.buffer_length = size;
s.info.show_opcodes = true;
if (s.info.cap_arch >= 0 && cap_disas_host(&s.info, code, size)) {
return;
+3 -5
View File
@@ -1972,11 +1972,9 @@ print_insn_hppa (bfd_vma memaddr, disassemble_info *info)
insn = bfd_getb32 (buffer);
if (info->show_opcodes) {
info->fprintf_func(info->stream, " %02x %02x %02x %02x ",
(insn >> 24) & 0xff, (insn >> 16) & 0xff,
(insn >> 8) & 0xff, insn & 0xff);
}
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)
{
+97 -97
View File
@@ -36,6 +36,35 @@ typedef uint32_t uint32;
typedef uint16_t uint16;
typedef uint64_t img_address;
typedef enum {
instruction,
call_instruction,
branch_instruction,
return_instruction,
reserved_block,
pool,
} TABLE_ENTRY_TYPE;
typedef enum {
MIPS64_ = 0x00000001,
XNP_ = 0x00000002,
XMMS_ = 0x00000004,
EVA_ = 0x00000008,
DSP_ = 0x00000010,
MT_ = 0x00000020,
EJTAG_ = 0x00000040,
TLBINV_ = 0x00000080,
CP0_ = 0x00000100,
CP1_ = 0x00000200,
CP2_ = 0x00000400,
UDI_ = 0x00000800,
MCU_ = 0x00001000,
VZ_ = 0x00002000,
TLB_ = 0x00004000,
MVH_ = 0x00008000,
ALL_ATTRIBUTES = 0xffffffffull,
} TABLE_ATTRIBUTE_TYPE;
typedef struct Dis_info {
img_address m_pc;
fprintf_function fprintf_func;
@@ -43,6 +72,22 @@ typedef struct Dis_info {
sigjmp_buf buf;
} Dis_info;
typedef bool (*conditional_function)(uint64 instruction);
typedef char * (*disassembly_function)(uint64 instruction,
Dis_info *info);
typedef struct Pool {
TABLE_ENTRY_TYPE type;
const struct Pool *next_table;
int next_table_size;
int instructions_size;
uint64 mask;
uint64 value;
disassembly_function disassembly;
conditional_function condition;
uint64 attributes;
} Pool;
#define IMGASSERTONCE(test)
@@ -499,6 +544,58 @@ static uint64 extract_op_code_value(const uint16 *data, int size)
}
/*
* Recurse through tables until the instruction is found then return
* the string and size
*
* inputs:
* pointer to a word stream,
* disassember table and size
* returns:
* instruction size - negative is error
* disassembly string - on error will constain error string
*/
static int Disassemble(const uint16 *data, char **dis,
TABLE_ENTRY_TYPE *type, const Pool *table,
int table_size, Dis_info *info)
{
for (int i = 0; i < table_size; i++) {
uint64 op_code = extract_op_code_value(data,
table[i].instructions_size);
if ((op_code & table[i].mask) == table[i].value) {
/* possible match */
conditional_function cond = table[i].condition;
if ((cond == NULL) || cond(op_code)) {
if (table[i].type == pool) {
return Disassemble(data, dis, type,
table[i].next_table,
table[i].next_table_size,
info);
} else if ((table[i].type == instruction) ||
(table[i].type == call_instruction) ||
(table[i].type == branch_instruction) ||
(table[i].type == return_instruction)) {
disassembly_function dis_fn = table[i].disassembly;
if (dis_fn == 0) {
*dis = g_strdup(
"disassembler failure - bad table entry");
return -6;
}
*type = table[i].type;
*dis = dis_fn(op_code, info);
return table[i].instructions_size;
} else {
*dis = g_strdup("reserved instruction");
return -2;
}
}
}
}
*dis = g_strdup("failed to disassemble");
return -1; /* failed to disassemble */
}
static uint64 extract_code_18_to_0(uint64 instruction)
{
uint64 value = 0;
@@ -16116,51 +16213,6 @@ static char *YIELD(uint64 instruction, Dis_info *info)
*
*/
typedef enum {
instruction,
call_instruction,
branch_instruction,
return_instruction,
reserved_block,
pool,
} TABLE_ENTRY_TYPE;
typedef enum {
MIPS64_ = 0x00000001,
XNP_ = 0x00000002,
XMMS_ = 0x00000004,
EVA_ = 0x00000008,
DSP_ = 0x00000010,
MT_ = 0x00000020,
EJTAG_ = 0x00000040,
TLBINV_ = 0x00000080,
CP0_ = 0x00000100,
CP1_ = 0x00000200,
CP2_ = 0x00000400,
UDI_ = 0x00000800,
MCU_ = 0x00001000,
VZ_ = 0x00002000,
TLB_ = 0x00004000,
MVH_ = 0x00008000,
ALL_ATTRIBUTES = 0xffffffffull,
} TABLE_ATTRIBUTE_TYPE;
typedef bool (*conditional_function)(uint64 instruction);
typedef char * (*disassembly_function)(uint64 instruction,
Dis_info *info);
typedef struct Pool {
TABLE_ENTRY_TYPE type;
const struct Pool *next_table;
int next_table_size;
int instructions_size;
uint64 mask;
uint64 value;
disassembly_function disassembly;
conditional_function condition;
uint64 attributes;
} Pool;
static const Pool P_SYSCALL[2] = {
{ instruction , 0 , 0 , 32,
0xfffc0000, 0x00080000, &SYSCALL_32_ , 0,
@@ -21855,58 +21907,6 @@ static const Pool MAJOR[2] = {
0x0 }, /* P16 */
};
/*
* Recurse through tables until the instruction is found then return
* the string and size
*
* inputs:
* pointer to a word stream,
* disassember table and size
* returns:
* instruction size - negative is error
* disassembly string - on error will constain error string
*/
static int Disassemble(const uint16 *data, char **dis,
TABLE_ENTRY_TYPE *type, const Pool *table,
int table_size, Dis_info *info)
{
for (int i = 0; i < table_size; i++) {
uint64 op_code = extract_op_code_value(data,
table[i].instructions_size);
if ((op_code & table[i].mask) == table[i].value) {
/* possible match */
conditional_function cond = table[i].condition;
if ((cond == NULL) || cond(op_code)) {
if (table[i].type == pool) {
return Disassemble(data, dis, type,
table[i].next_table,
table[i].next_table_size,
info);
} else if ((table[i].type == instruction) ||
(table[i].type == call_instruction) ||
(table[i].type == branch_instruction) ||
(table[i].type == return_instruction)) {
disassembly_function dis_fn = table[i].disassembly;
if (dis_fn == 0) {
*dis = g_strdup(
"disassembler failure - bad table entry");
return -6;
}
*type = table[i].type;
*dis = dis_fn(op_code, info);
return table[i].instructions_size;
} else {
*dis = g_strdup("reserved instruction");
return -2;
}
}
}
}
*dis = g_strdup("failed to disassemble");
return -1; /* failed to disassemble */
}
static bool nanomips_dis(const uint16_t *data, char **buf, Dis_info *info)
{
TABLE_ENTRY_TYPE type;
+14 -79
View File
@@ -2190,22 +2190,7 @@ static const char *csr_name(int csrno)
case 0x0383: return "mibound";
case 0x0384: return "mdbase";
case 0x0385: return "mdbound";
case 0x03a0: return "pmpcfg0";
case 0x03a1: return "pmpcfg1";
case 0x03a2: return "pmpcfg2";
case 0x03a3: return "pmpcfg3";
case 0x03a4: return "pmpcfg4";
case 0x03a5: return "pmpcfg5";
case 0x03a6: return "pmpcfg6";
case 0x03a7: return "pmpcfg7";
case 0x03a8: return "pmpcfg8";
case 0x03a9: return "pmpcfg9";
case 0x03aa: return "pmpcfg10";
case 0x03ab: return "pmpcfg11";
case 0x03ac: return "pmpcfg12";
case 0x03ad: return "pmpcfg13";
case 0x03ae: return "pmpcfg14";
case 0x03af: return "pmpcfg15";
case 0x03a0: return "pmpcfg3";
case 0x03b0: return "pmpaddr0";
case 0x03b1: return "pmpaddr1";
case 0x03b2: return "pmpaddr2";
@@ -2222,54 +2207,6 @@ static const char *csr_name(int csrno)
case 0x03bd: return "pmpaddr13";
case 0x03be: return "pmpaddr14";
case 0x03bf: return "pmpaddr15";
case 0x03c0: return "pmpaddr16";
case 0x03c1: return "pmpaddr17";
case 0x03c2: return "pmpaddr18";
case 0x03c3: return "pmpaddr19";
case 0x03c4: return "pmpaddr20";
case 0x03c5: return "pmpaddr21";
case 0x03c6: return "pmpaddr22";
case 0x03c7: return "pmpaddr23";
case 0x03c8: return "pmpaddr24";
case 0x03c9: return "pmpaddr25";
case 0x03ca: return "pmpaddr26";
case 0x03cb: return "pmpaddr27";
case 0x03cc: return "pmpaddr28";
case 0x03cd: return "pmpaddr29";
case 0x03ce: return "pmpaddr30";
case 0x03cf: return "pmpaddr31";
case 0x03d0: return "pmpaddr32";
case 0x03d1: return "pmpaddr33";
case 0x03d2: return "pmpaddr34";
case 0x03d3: return "pmpaddr35";
case 0x03d4: return "pmpaddr36";
case 0x03d5: return "pmpaddr37";
case 0x03d6: return "pmpaddr38";
case 0x03d7: return "pmpaddr39";
case 0x03d8: return "pmpaddr40";
case 0x03d9: return "pmpaddr41";
case 0x03da: return "pmpaddr42";
case 0x03db: return "pmpaddr43";
case 0x03dc: return "pmpaddr44";
case 0x03dd: return "pmpaddr45";
case 0x03de: return "pmpaddr46";
case 0x03df: return "pmpaddr47";
case 0x03e0: return "pmpaddr48";
case 0x03e1: return "pmpaddr49";
case 0x03e2: return "pmpaddr50";
case 0x03e3: return "pmpaddr51";
case 0x03e4: return "pmpaddr52";
case 0x03e5: return "pmpaddr53";
case 0x03e6: return "pmpaddr54";
case 0x03e7: return "pmpaddr55";
case 0x03e8: return "pmpaddr56";
case 0x03e9: return "pmpaddr57";
case 0x03ea: return "pmpaddr58";
case 0x03eb: return "pmpaddr59";
case 0x03ec: return "pmpaddr60";
case 0x03ed: return "pmpaddr61";
case 0x03ee: return "pmpaddr62";
case 0x03ef: return "pmpaddr63";
case 0x0780: return "mtohost";
case 0x0781: return "mfromhost";
case 0x0782: return "mreset";
@@ -5255,21 +5192,19 @@ print_insn_riscv(bfd_vma memaddr, struct disassemble_info *info, rv_isa isa)
}
}
if (info->show_opcodes) {
switch (len) {
case 2:
(*info->fprintf_func)(info->stream, INST_FMT_2, inst);
break;
case 4:
(*info->fprintf_func)(info->stream, INST_FMT_4, inst);
break;
case 6:
(*info->fprintf_func)(info->stream, INST_FMT_6, inst);
break;
default:
(*info->fprintf_func)(info->stream, INST_FMT_8, inst);
break;
}
switch (len) {
case 2:
(*info->fprintf_func)(info->stream, INST_FMT_2, inst);
break;
case 4:
(*info->fprintf_func)(info->stream, INST_FMT_4, inst);
break;
case 6:
(*info->fprintf_func)(info->stream, INST_FMT_6, inst);
break;
default:
(*info->fprintf_func)(info->stream, INST_FMT_8, inst);
break;
}
disasm_inst(buf, sizeof(buf), isa, memaddr, inst,
+19 -32
View File
@@ -36,6 +36,22 @@ and will cause a warning.
The replacement for the ``nodelay`` short-form boolean option is ``nodelay=on``
rather than ``delay=off``.
``-smp`` ("parameter=0" SMP configurations) (since 6.2)
'''''''''''''''''''''''''''''''''''''''''''''''''''''''
Specified CPU topology parameters must be greater than zero.
In the SMP configuration, users should either provide a CPU topology
parameter with a reasonable value (greater than zero) or just omit it
and QEMU will compute the missing value.
However, historically it was implicitly allowed for users to provide
a parameter with zero value, which is meaningless and could also possibly
cause unexpected results in the -smp parsing. So support for this kind of
configurations (e.g. -smp 8,sockets=0) is deprecated since 6.2 and will
be removed in the near future, users have to ensure that all the topology
members described with -smp are greater than zero.
Plugin argument passing through ``arg=<string>`` (since 6.1)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
@@ -47,20 +63,6 @@ as short-form boolean values, and passed to plugins as ``arg_name=on``.
However, short-form booleans are deprecated and full explicit ``arg_name=on``
form is preferred.
``-smp`` (Unsupported "parameter=1" SMP configurations) (since 9.0)
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Specified CPU topology parameters must be supported by the machine.
In the SMP configuration, users should provide the CPU topology parameters that
are supported by the target machine.
However, historically it was allowed for users to specify the unsupported
topology parameter as "1", which is meaningless. So support for this kind of
configurations (e.g. -smp drawers=1,books=1,clusters=1 for x86 PC machine) is
marked deprecated since 9.0, users have to ensure that all the topology members
described with -smp are supported by the target machine.
User-mode emulator command line arguments
-----------------------------------------
@@ -237,28 +239,13 @@ The Nios II architecture is orphan.
The machine is no longer in existence and has been long unmaintained
in QEMU. This also holds for the TC51828 16MiB flash that it uses.
``pseries-2.1`` up to ``pseries-2.12`` (since 9.0)
``pseries-2.1`` up to ``pseries-2.11`` (since 9.0)
''''''''''''''''''''''''''''''''''''''''''''''''''
Older pseries machines before version 3.0 have undergone many changes
Older pseries machines before version 2.12 have undergone many changes
to correct issues, mostly regarding migration compatibility. These are
no longer maintained and removing them will make the code easier to
read and maintain. Use versions 3.0 and above as a replacement.
Arm machines ``akita``, ``borzoi``, ``cheetah``, ``connex``, ``mainstone``, ``n800``, ``n810``, ``spitz``, ``terrier``, ``tosa``, ``verdex``, ``z2`` (since 9.0)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
QEMU includes models of some machine types where the QEMU code that
emulates their SoCs is very old and unmaintained. This code is now
blocking our ability to move forward with various changes across
the codebase, and over many years nobody has been interested in
trying to modernise it. We don't expect any of these machines to have
a large number of users, because they're all modelling hardware that
has now passed away into history. We are therefore dropping support
for all machine types using the PXA2xx and OMAP2 SoCs. We are also
dropping the ``cheetah`` OMAP1 board, because we don't have any
test images for it and don't know of anybody who does; the ``sx1``
and ``sx1-v1`` OMAP1 machines remain supported for now.
read and maintain. Use versions 2.12 and above as a replacement.
Backend options
---------------
-15
View File
@@ -489,21 +489,6 @@ The ``-singlestep`` option has been turned into an accelerator property,
and given a name that better reflects what it actually does.
Use ``-accel tcg,one-insn-per-tb=on`` instead.
``-smp`` ("parameter=0" SMP configurations) (removed in 9.0)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Specified CPU topology parameters must be greater than zero.
In the SMP configuration, users should either provide a CPU topology
parameter with a reasonable value (greater than zero) or just omit it
and QEMU will compute the missing value.
However, historically it was implicitly allowed for users to provide
a parameter with zero value, which is meaningless and could also possibly
cause unexpected results in the -smp parsing. So support for this kind of
configurations (e.g. -smp 8,sockets=0) is removed since 9.0, users have
to ensure that all the topology members described with -smp are greater
than zero.
User-mode emulator command line arguments
-----------------------------------------
+1 -1
View File
@@ -88,7 +88,7 @@ default_role = 'any'
# General information about the project.
project = u'QEMU'
copyright = u'2024, The QEMU Project Developers'
copyright = u'2023, The QEMU Project Developers'
author = u'The QEMU Project Developers'
# The version info for the project you're documenting, acts as replacement for
+16 -39
View File
@@ -1,48 +1,26 @@
=============================================================================
ACPI/SMBIOS avocado tests using biosbits
=============================================================================
************
Introduction
************
Biosbits is a software written by Josh Triplett that can be downloaded
from https://biosbits.org/. The github codebase can be found
`here <https://github.com/biosbits/bits/tree/master>`__. It is a software that
executes the bios components such as acpi and smbios tables directly through
acpica bios interpreter (a freely available C based library written by Intel,
`here <https://github.com/biosbits/bits/tree/master>`__. It is a software that executes
the bios components such as acpi and smbios tables directly through acpica
bios interpreter (a freely available C based library written by Intel,
downloadable from https://acpica.org/ and is included with biosbits) without an
operating system getting involved in between. Bios-bits has python integration
with grub so actual routines that executes bios components can be written in
python instead of bash-ish (grub's native scripting language).
operating system getting involved in between.
There are several advantages to directly testing the bios in a real physical
machine or in a VM as opposed to indirectly discovering bios issues through the
operating system (the OS). Operating systems tend to bypass bios problems and
hide them from the end user. We have more control of what we wanted to test and
how by being as close to the bios on a running system as possible without a
complicated software component such as an operating system coming in between.
Another issue is that we cannot exercise bios components such as ACPI and
SMBIOS without being in the highest hardware privilege level, ring 0 for
example in case of x86. Since the OS executes from ring 0 whereas normal user
land software resides in unprivileged ring 3, operating system must be modified
in order to write our test routines that exercise and test the bios. This is
not possible in all cases. Lastly, test frameworks and routines are preferably
written using a high level scripting language such as python. OSes and
OS modules are generally written using low level languages such as C and
low level assembly machine language. Writing test routines in a low level
language makes things more cumbersome. These and other reasons makes using
bios-bits very attractive for testing bioses. More details on the inspiration
for developing biosbits and its real life uses can be found in [#a]_ and [#b]_.
machine or VM as opposed to indirectly discovering bios issues through the
operating system. For one thing, the OSes tend to hide bios problems from the
end user. The other is that we have more control of what we wanted to test
and how by directly using acpica interpreter on top of the bios on a running
system. More details on the inspiration for developing biosbits and its real
life uses can be found in [#a]_ and [#b]_.
For QEMU, we maintain a fork of bios bits in gitlab along with all the
dependent submodules `here <https://gitlab.com/qemu-project/biosbits-bits>`__.
dependent submodules here: https://gitlab.com/qemu-project/biosbits-bits
This fork contains numerous fixes, a newer acpica and changes specific to
running this avocado QEMU tests using bits. The author of this document
is the sole maintainer of the QEMU fork of bios bits repository. For more
information, please see author's `FOSDEM talk on this bios-bits based test
framework <https://fosdem.org/2024/schedule/event/fosdem-2024-2262-exercising-qemu-generated-acpi-smbios-tables-using-biosbits-from-within-a-guest-vm-/>`__.
*********************************
Description of the test framework
*********************************
is the sole maintainer of the QEMU fork of bios bits repo.
Under the directory ``tests/avocado/``, ``acpi-bits.py`` is a QEMU avocado
test that drives all this.
@@ -142,9 +120,8 @@ Under ``tests/avocado/`` as the root we have:
(b) Add a SPDX license header.
(c) Perform modifications to the test.
Commits (a), (b) and (c) preferably should go under separate commits so that
the original test script and the changes we have made are separated and
clear. (a) and (b) can sometimes be combined into a single step.
Commits (a), (b) and (c) should go under separate commits so that the original
test script and the changes we have made are separated and clear.
The test framework will then use your modified test script to run the test.
No further changes would be needed. Please check the logs to make sure that
@@ -164,4 +141,4 @@ References:
-----------
.. [#a] https://blog.linuxplumbersconf.org/2011/ocw/system/presentations/867/original/bits.pdf
.. [#b] https://www.youtube.com/watch?v=36QIepyUuhg
.. [#c] https://fosdem.org/2024/schedule/event/fosdem-2024-2262-exercising-qemu-generated-acpi-smbios-tables-using-biosbits-from-within-a-guest-vm-/
+1 -1
View File
@@ -119,7 +119,7 @@ The only guarantees that you can rely upon in this case are:
ordinary accesses instead cause data races if they are concurrent with
other accesses of which at least one is a write. In order to ensure this,
the compiler will not optimize accesses out of existence, create unsolicited
accesses, or perform other similar optimizations.
accesses, or perform other similar optimzations.
- acquire operations will appear to happen, with respect to the other
components of the system, before all the LOAD or STORE operations
+1 -1
View File
@@ -115,7 +115,7 @@ CI pipeline.
QEMU_JOB_SKIPPED
~~~~~~~~~~~~~~~~
The job is not reliably successful in general, so is not
The job is not reliably successsful in general, so is not
currently suitable to be run by default. Ideally this should
be a temporary marker until the problems can be addressed, or
the job permanently removed.
-4
View File
@@ -279,10 +279,6 @@ You can change the multiplier and divider of a clock at runtime,
so you can use this to model clock controller devices which
have guest-programmable frequency multipliers or dividers.
Similarly to ``clock_set()``, ``clock_set_mul_div()`` returns ``true`` if
the clock state was modified; that is, if the multiplier or the diviser
or both were changed by the call.
Note that ``clock_set_mul_div()`` does not automatically call
``clock_propagate()``. If you make a runtime change to the
multiplier or divider you must call clock_propagate() yourself.
-147
View File
@@ -1,147 +0,0 @@
CheckPoint and Restart (CPR)
============================
CPR is the umbrella name for a set of migration modes in which the
VM is migrated to a new QEMU instance on the same host. It is
intended for use when the goal is to update host software components
that run the VM, such as QEMU or even the host kernel. At this time,
cpr-reboot is the only available mode.
Because QEMU is restarted on the same host, with access to the same
local devices, CPR is allowed in certain cases where normal migration
would be blocked. However, the user must not modify the contents of
guest block devices between quitting old QEMU and starting new QEMU.
CPR unconditionally stops VM execution before memory is saved, and
thus does not depend on any form of dirty page tracking.
cpr-reboot mode
---------------
In this mode, QEMU stops the VM, and writes VM state to the migration
URI, which will typically be a file. After quitting QEMU, the user
resumes by running QEMU with the ``-incoming`` option. Because the
old and new QEMU instances are not active concurrently, the URI cannot
be a type that streams data from one instance to the other.
Guest RAM can be saved in place if backed by shared memory, or can be
copied to a file. The former is more efficient and is therefore
preferred.
After state and memory are saved, the user may update userland host
software before restarting QEMU and resuming the VM. Further, if
the RAM is backed by persistent shared memory, such as a DAX device,
then the user may reboot to a new host kernel before restarting QEMU.
This mode supports VFIO devices provided the user first puts the
guest in the suspended runstate, such as by issuing the
``guest-suspend-ram`` command to the QEMU guest agent. The agent
must be pre-installed in the guest, and the guest must support
suspend to RAM. Beware that suspension can take a few seconds, so
the user should poll to see the suspended state before proceeding
with the CPR operation.
Usage
^^^^^
It is recommended that guest RAM be backed with some type of shared
memory, such as ``memory-backend-file,share=on``, and that the
``x-ignore-shared`` capability be set. This combination allows memory
to be saved in place. Otherwise, after QEMU stops the VM, all guest
RAM is copied to the migration URI.
Outgoing:
* Set the migration mode parameter to ``cpr-reboot``.
* Set the ``x-ignore-shared`` capability if desired.
* Issue the ``migrate`` command. It is recommended the the URI be a
``file`` type, but one can use other types such as ``exec``,
provided the command captures all the data from the outgoing side,
and provides all the data to the incoming side.
* Quit when QEMU reaches the postmigrate state.
Incoming:
* Start QEMU with the ``-incoming defer`` option.
* Set the migration mode parameter to ``cpr-reboot``.
* Set the ``x-ignore-shared`` capability if desired.
* Issue the ``migrate-incoming`` command.
* If the VM was running when the outgoing ``migrate`` command was
issued, then QEMU automatically resumes VM execution.
Example 1
^^^^^^^^^
::
# qemu-kvm -monitor stdio
-object memory-backend-file,id=ram0,size=4G,mem-path=/dev/dax0.0,align=2M,share=on -m 4G
...
(qemu) info status
VM status: running
(qemu) migrate_set_parameter mode cpr-reboot
(qemu) migrate_set_capability x-ignore-shared on
(qemu) migrate -d file:vm.state
(qemu) info status
VM status: paused (postmigrate)
(qemu) quit
### optionally update kernel and reboot
# systemctl kexec
kexec_core: Starting new kernel
...
# qemu-kvm ... -incoming defer
(qemu) info status
VM status: paused (inmigrate)
(qemu) migrate_set_parameter mode cpr-reboot
(qemu) migrate_set_capability x-ignore-shared on
(qemu) migrate_incoming file:vm.state
(qemu) info status
VM status: running
Example 2: VFIO
^^^^^^^^^^^^^^^
::
# qemu-kvm -monitor stdio
-object memory-backend-file,id=ram0,size=4G,mem-path=/dev/dax0.0,align=2M,share=on -m 4G
-device vfio-pci, ...
-chardev socket,id=qga0,path=qga.sock,server=on,wait=off
-device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0
...
(qemu) info status
VM status: running
# echo '{"execute":"guest-suspend-ram"}' | ncat --send-only -U qga.sock
(qemu) info status
VM status: paused (suspended)
(qemu) migrate_set_parameter mode cpr-reboot
(qemu) migrate_set_capability x-ignore-shared on
(qemu) migrate -d file:vm.state
(qemu) info status
VM status: paused (postmigrate)
(qemu) quit
### optionally update kernel and reboot
# systemctl kexec
kexec_core: Starting new kernel
...
# qemu-kvm ... -incoming defer
(qemu) info status
VM status: paused (inmigrate)
(qemu) migrate_set_parameter mode cpr-reboot
(qemu) migrate_set_capability x-ignore-shared on
(qemu) migrate_incoming file:vm.state
(qemu) info status
VM status: paused (suspended)
(qemu) system_wakeup
(qemu) info status
VM status: running
Caveats
^^^^^^^
cpr-reboot mode may not be used with postcopy, background-snapshot,
or COLO.
-2
View File
@@ -10,5 +10,3 @@ Migration has plenty of features to support different use cases.
dirty-limit
vfio
virtio
mapped-ram
CPR
+1 -2
View File
@@ -44,8 +44,7 @@ over any transport.
- file migration: do the migration using a file that is passed to QEMU
by path. A file offset option is supported to allow a management
application to add its own metadata to the start of the file without
QEMU interference. Note that QEMU does not flush cached file
data/metadata at the end of migration.
QEMU interference.
In addition, support is included for migration using RDMA, which
transports the page data using ``RDMA``, where the hardware takes care of
-138
View File
@@ -1,138 +0,0 @@
Mapped-ram
==========
Mapped-ram is a new stream format for the RAM section designed to
supplement the existing ``file:`` migration and make it compatible
with ``multifd``. This enables parallel migration of a guest's RAM to
a file.
The core of the feature is to ensure that RAM pages are mapped
directly to offsets in the resulting migration file. This enables the
``multifd`` threads to write exclusively to those offsets even if the
guest is constantly dirtying pages (i.e. live migration). Another
benefit is that the resulting file will have a bounded size, since
pages which are dirtied multiple times will always go to a fixed
location in the file, rather than constantly being added to a
sequential stream. Having the pages at fixed offsets also allows the
usage of O_DIRECT for save/restore of the migration stream as the
pages are ensured to be written respecting O_DIRECT alignment
restrictions (direct-io support not yet implemented).
Usage
-----
On both source and destination, enable the ``multifd`` and
``mapped-ram`` capabilities:
``migrate_set_capability multifd on``
``migrate_set_capability mapped-ram on``
Use a ``file:`` URL for migration:
``migrate file:/path/to/migration/file``
Mapped-ram migration is best done non-live, i.e. by stopping the VM on
the source side before migrating.
Use-cases
---------
The mapped-ram feature was designed for use cases where the migration
stream will be directed to a file in the filesystem and not
immediately restored on the destination VM [#]_. These could be
thought of as snapshots. We can further categorize them into live and
non-live.
- Non-live snapshot
If the use case requires a VM to be stopped before taking a snapshot,
that's the ideal scenario for mapped-ram migration. Not having to
track dirty pages, the migration will write the RAM pages to the disk
as fast as it can.
Note: if a snapshot is taken of a running VM, but the VM will be
stopped after the snapshot by the admin, then consider stopping it
right before the snapshot to take benefit of the performance gains
mentioned above.
- Live snapshot
If the use case requires that the VM keeps running during and after
the snapshot operation, then mapped-ram migration can still be used,
but will be less performant. Other strategies such as
background-snapshot should be evaluated as well. One benefit of
mapped-ram in this scenario is portability since background-snapshot
depends on async dirty tracking (KVM_GET_DIRTY_LOG) which is not
supported outside of Linux.
.. [#] While this same effect could be obtained with the usage of
snapshots or the ``file:`` migration alone, mapped-ram provides
a performance increase for VMs with larger RAM sizes (10s to
100s of GiBs), specially if the VM has been stopped beforehand.
RAM section format
------------------
Instead of having a sequential stream of pages that follow the
RAMBlock headers, the dirty pages for a RAMBlock follow its header
instead. This ensures that each RAM page has a fixed offset in the
resulting migration file.
A bitmap is introduced to track which pages have been written in the
migration file. Pages are written at a fixed location for every
ramblock. Zero pages are ignored as they'd be zero in the destination
migration as well.
::
Without mapped-ram: With mapped-ram:
--------------------- --------------------------------
| ramblock 1 header | | ramblock 1 header |
--------------------- --------------------------------
| ramblock 2 header | | ramblock 1 mapped-ram header |
--------------------- --------------------------------
| ... | | padding to next 1MB boundary |
--------------------- | ... |
| ramblock n header | --------------------------------
--------------------- | ramblock 1 pages |
| RAM_SAVE_FLAG_EOS | | ... |
--------------------- --------------------------------
| stream of pages | | ramblock 2 header |
| (iter 1) | --------------------------------
| ... | | ramblock 2 mapped-ram header |
--------------------- --------------------------------
| RAM_SAVE_FLAG_EOS | | padding to next 1MB boundary |
--------------------- | ... |
| stream of pages | --------------------------------
| (iter 2) | | ramblock 2 pages |
| ... | | ... |
--------------------- --------------------------------
| ... | | ... |
--------------------- --------------------------------
| RAM_SAVE_FLAG_EOS |
--------------------------------
| ... |
--------------------------------
where:
- ramblock header: the generic information for a ramblock, such as
idstr, used_len, etc.
- ramblock mapped-ram header: the information added by this feature:
bitmap of pages written, bitmap size and offset of pages in the
migration file.
Restrictions
------------
Since pages are written to their relative offsets and out of order
(due to the memory dirtying patterns), streaming channels such as
sockets are not supported. A seekable channel such as a file is
required. This can be verified in the QIOChannel by the presence of
the QIO_CHANNEL_FEATURE_SEEKABLE.
The improvements brought by this feature apply only to guest physical
RAM. Other types of memory such as VRAM are migrated as part of device
states.
-119
View File
@@ -1,119 +0,0 @@
Nested PAPR API (aka KVM on PowerVM)
====================================
This API aims at providing support to enable nested virtualization with
KVM on PowerVM. While the existing support for nested KVM on PowerNV was
introduced with cap-nested-hv option, however, with a slight design change,
to enable this on papr/pseries, a new cap-nested-papr option is added. eg:
qemu-system-ppc64 -cpu POWER10 -machine pseries,cap-nested-papr=true ...
Work by:
Michael Neuling <mikey@neuling.org>
Vaibhav Jain <vaibhav@linux.ibm.com>
Jordan Niethe <jniethe5@gmail.com>
Harsh Prateek Bora <harshpb@linux.ibm.com>
Shivaprasad G Bhat <sbhat@linux.ibm.com>
Kautuk Consul <kconsul@linux.vnet.ibm.com>
Below taken from the kernel documentation:
Introduction
============
This document explains how a guest operating system can act as a
hypervisor and run nested guests through the use of hypercalls, if the
hypervisor has implemented them. The terms L0, L1, and L2 are used to
refer to different software entities. L0 is the hypervisor mode entity
that would normally be called the "host" or "hypervisor". L1 is a
guest virtual machine that is directly run under L0 and is initiated
and controlled by L0. L2 is a guest virtual machine that is initiated
and controlled by L1 acting as a hypervisor. A significant design change
wrt existing API is that now the entire L2 state is maintained within L0.
Existing Nested-HV API
======================
Linux/KVM has had support for Nesting as an L0 or L1 since 2018
The L0 code was added::
commit 8e3f5fc1045dc49fd175b978c5457f5f51e7a2ce
Author: Paul Mackerras <paulus@ozlabs.org>
Date: Mon Oct 8 16:31:03 2018 +1100
KVM: PPC: Book3S HV: Framework and hcall stubs for nested virtualization
The L1 code was added::
commit 360cae313702cdd0b90f82c261a8302fecef030a
Author: Paul Mackerras <paulus@ozlabs.org>
Date: Mon Oct 8 16:31:04 2018 +1100
KVM: PPC: Book3S HV: Nested guest entry via hypercall
This API works primarily using a signal hcall h_enter_nested(). This
call made by the L1 to tell the L0 to start an L2 vCPU with the given
state. The L0 then starts this L2 and runs until an L2 exit condition
is reached. Once the L2 exits, the state of the L2 is given back to
the L1 by the L0. The full L2 vCPU state is always transferred from
and to L1 when the L2 is run. The L0 doesn't keep any state on the L2
vCPU (except in the short sequence in the L0 on L1 -> L2 entry and L2
-> L1 exit).
The only state kept by the L0 is the partition table. The L1 registers
it's partition table using the h_set_partition_table() hcall. All
other state held by the L0 about the L2s is cached state (such as
shadow page tables).
The L1 may run any L2 or vCPU without first informing the L0. It
simply starts the vCPU using h_enter_nested(). The creation of L2s and
vCPUs is done implicitly whenever h_enter_nested() is called.
In this document, we call this existing API the v1 API.
New PAPR API
===============
The new PAPR API changes from the v1 API such that the creating L2 and
associated vCPUs is explicit. In this document, we call this the v2
API.
h_enter_nested() is replaced with H_GUEST_VCPU_RUN(). Before this can
be called the L1 must explicitly create the L2 using h_guest_create()
and any associated vCPUs() created with h_guest_create_vCPU(). Getting
and setting vCPU state can also be performed using h_guest_{g|s}et
hcall.
The basic execution flow is for an L1 to create an L2, run it, and
delete it is:
- L1 and L0 negotiate capabilities with H_GUEST_{G,S}ET_CAPABILITIES()
(normally at L1 boot time).
- L1 requests the L0 to create an L2 with H_GUEST_CREATE() and receives a token
- L1 requests the L0 to create an L2 vCPU with H_GUEST_CREATE_VCPU()
- L1 and L0 communicate the vCPU state using the H_GUEST_{G,S}ET() hcall
- L1 requests the L0 to run the vCPU using H_GUEST_RUN_VCPU() hcall
- L1 deletes L2 with H_GUEST_DELETE()
For more details, please refer:
[1] Linux Kernel documentation (upstream documentation commit):
commit 476652297f94a2e5e5ef29e734b0da37ade94110
Author: Michael Neuling <mikey@neuling.org>
Date: Thu Sep 14 13:06:00 2023 +1000
docs: powerpc: Document nested KVM on POWER
Document support for nested KVM on POWER using the existing API as well
as the new PAPR API. This includes the new HCALL interface and how it
used by KVM.
Signed-off-by: Michael Neuling <mikey@neuling.org>
Signed-off-by: Jordan Niethe <jniethe5@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20230914030600.16993-12-jniethe5@gmail.com
+1 -5
View File
@@ -996,8 +996,7 @@ line "Features:", like this::
A tagged section begins with a paragraph that starts with one of the
following words: "Note:"/"Notes:", "Since:", "Example:"/"Examples:",
"Returns:", "Errors:", "TODO:". It ends with the start of a new
section.
"Returns:", "TODO:". It ends with the start of a new section.
The second and subsequent lines of tagged sections must be indented
like this::
@@ -1008,9 +1007,6 @@ like this::
# Duis aute irure dolor in reprehenderit in voluptate velit esse
# cillum dolore eu fugiat nulla pariatur.
"Returns" and "Errors" sections are only valid for commands. They
document the success and the error response, respectively.
A "Since: x.y.z" tagged section lists the release that introduced the
definition.
+2 -1
View File
@@ -357,7 +357,8 @@ probes::
scripts/tracetool.py --backends=dtrace --format=stap \
--binary path/to/qemu-binary \
--probe-prefix qemu.system.x86_64 \
--target-type system \
--target-name x86_64 \
--group=all \
trace-events-all \
qemu.stp
+293 -193
View File
@@ -66,13 +66,12 @@ Then, in a different terminal::
"version": {
"qemu": {
"micro": 50,
"minor": 2,
"major": 8
"minor": 15,
"major": 0
},
"package": ...
"package": ""
},
"capabilities": [
"oob"
]
}
}
@@ -108,14 +107,10 @@ The first step is defining the command in the appropriate QAPI schema
module. We pick module qapi/misc.json, and add the following line at
the bottom::
##
# @hello-world:
#
# Since: 9.0
##
{ 'command': 'hello-world' }
The "command" keyword defines a new QMP command. It instructs QAPI to
The "command" keyword defines a new QMP command. It's an JSON object. All
schema entries are JSON objects. The line above will instruct the QAPI to
generate any prototypes and the necessary code to marshal and unmarshal
protocol data.
@@ -137,70 +132,57 @@ There are a few things to be noticed:
3. It takes an "Error \*\*" argument. This is required. Later we will see how to
return errors and take additional arguments. The Error argument should not
be touched if the command doesn't return errors
4. We won't add the function's prototype. That's automatically done by QAPI
4. We won't add the function's prototype. That's automatically done by the QAPI
5. Printing to the terminal is discouraged for QMP commands, we do it here
because it's the easiest way to demonstrate a QMP command
You're done. Now build QEMU, run it as suggested in the "Testing" section,
You're done. Now build qemu, run it as suggested in the "Testing" section,
and then type the following QMP command::
{ "execute": "hello-world" }
Then check the terminal running QEMU and look for the "Hello, world" string. If
Then check the terminal running qemu and look for the "Hello, world" string. If
you don't see it then something went wrong.
Arguments
~~~~~~~~~
Let's add arguments to our "hello-world" command.
Let's add an argument called "message" to our "hello-world" command. The new
argument will contain the string to be printed to stdout. It's an optional
argument, if it's not present we print our default "Hello, World" string.
The first change we have to do is to modify the command specification in the
schema file to the following::
##
# @hello-world:
#
# @message: message to be printed (default: "Hello, world!")
#
# @times: how many times to print the message (default: 1)
#
# Since: 9.0
##
{ 'command': 'hello-world',
'data': { '*message': 'str', '*times': 'int' } }
{ 'command': 'hello-world', 'data': { '*message': 'str' } }
Notice the new 'data' member in the schema. It specifies an argument
'message' of QAPI type 'str', and an argument 'times' of QAPI type
'int'. Also notice the asterisk, it's used to mark the argument
optional.
Notice the new 'data' member in the schema. It's an JSON object whose each
element is an argument to the command in question. Also notice the asterisk,
it's used to mark the argument optional (that means that you shouldn't use it
for mandatory arguments). Finally, 'str' is the argument's type, which
stands for "string". The QAPI also supports integers, booleans, enumerations
and user defined types.
Now, let's update our C implementation in monitor/qmp-cmds.c::
void qmp_hello_world(const char *message, bool has_times, int64_t times,
Error **errp)
void qmp_hello_world(const char *message, Error **errp)
{
if (!message) {
message = "Hello, world";
}
if (!has_times) {
times = 1;
}
for (int i = 0; i < times; i++) {
if (message) {
printf("%s\n", message);
} else {
printf("Hello, world\n");
}
}
There are two important details to be noticed:
1. Optional arguments other than pointers are accompanied by a 'has\_'
boolean, which is set if the optional argument is present or false
otherwise
1. All optional arguments are accompanied by a 'has\_' boolean, which is set
if the optional argument is present or false otherwise
2. The C implementation signature must follow the schema's argument ordering,
which is defined by the "data" member
Time to test our new version of the "hello-world" command. Build QEMU, run it as
Time to test our new version of the "hello-world" command. Build qemu, run it as
described in the "Testing" section and then send two commands::
{ "execute": "hello-world" }
@@ -209,13 +191,13 @@ described in the "Testing" section and then send two commands::
}
}
{ "execute": "hello-world", "arguments": { "message": "We love QEMU" } }
{ "execute": "hello-world", "arguments": { "message": "We love qemu" } }
{
"return": {
}
}
You should see "Hello, world" and "We love QEMU" in the terminal running QEMU,
You should see "Hello, world" and "We love qemu" in the terminal running qemu,
if you don't see these strings, then something went wrong.
@@ -245,7 +227,7 @@ The first argument to the error_setg() function is the Error pointer
to pointer, which is passed to all QMP functions. The next argument is a human
description of the error, this is a free-form printf-like string.
Let's test the example above. Build QEMU, run it as defined in the "Testing"
Let's test the example above. Build qemu, run it as defined in the "Testing"
section, and then issue the following command::
{ "execute": "hello-world", "arguments": { "message": "all you need is love" } }
@@ -272,14 +254,44 @@ If the failure you want to report falls into one of the two cases above,
use error_set() with a second argument of an ErrorClass value.
Command Documentation
~~~~~~~~~~~~~~~~~~~~~
There's only one step missing to make "hello-world"'s implementation complete,
and that's its documentation in the schema file.
There are many examples of such documentation in the schema file already, but
here goes "hello-world"'s new entry for qapi/misc.json::
##
# @hello-world:
#
# Print a client provided string to the standard output stream.
#
# @message: string to be printed
#
# Returns: Nothing on success.
#
# Notes: if @message is not provided, the "Hello, world" string will
# be printed instead
#
# Since: <next qemu stable release, eg. 1.0>
##
{ 'command': 'hello-world', 'data': { '*message': 'str' } }
Please, note that the "Returns" clause is optional if a command doesn't return
any data nor any errors.
Implementing the HMP command
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now that the QMP command is in place, we can also make it available in the human
monitor (HMP).
With the introduction of QAPI, HMP commands make QMP calls. Most of the
time HMP commands are simple wrappers.
With the introduction of the QAPI, HMP commands make QMP calls. Most of the
time HMP commands are simple wrappers. All HMP commands implementation exist in
the monitor/hmp-cmds.c file.
Here's the implementation of the "hello-world" HMP command::
@@ -294,20 +306,18 @@ Here's the implementation of the "hello-world" HMP command::
}
}
Add it to monitor/hmp-cmds.c. Also, add its prototype to
include/monitor/hmp.h.
Also, you have to add the function's prototype to the hmp.h file.
There are four important points to be noticed:
There are three important points to be noticed:
1. The "mon" and "qdict" arguments are mandatory for all HMP functions. The
former is the monitor object. The latter is how the monitor passes
arguments entered by the user to the command implementation
2. We chose not to support the "times" argument in HMP
3. hmp_hello_world() performs error checking. In this example we just call
2. hmp_hello_world() performs error checking. In this example we just call
hmp_handle_error() which prints a message to the user, but we could do
more, like taking different actions depending on the error
qmp_hello_world() returns
4. The "err" variable must be initialized to NULL before performing the
3. The "err" variable must be initialized to NULL before performing the
QMP call
There's one last step to actually make the command available to monitor users,
@@ -330,17 +340,17 @@ To test this you have to open a user monitor and issue the "hello-world"
command. It might be instructive to check the command's documentation with
HMP's "help" command.
Please check the "-monitor" command-line option to know how to open a user
Please, check the "-monitor" command-line option to know how to open a user
monitor.
Writing more complex commands
-----------------------------
A QMP command is capable of returning any data QAPI supports like integers,
A QMP command is capable of returning any data the QAPI supports like integers,
strings, booleans, enumerations and user defined types.
In this section we will focus on user defined types. Please check the QAPI
In this section we will focus on user defined types. Please, check the QAPI
documentation for information about the other types.
@@ -362,7 +372,7 @@ data, it is not expected that machines will need to parse the result.
The overhead of defining a fine grained QAPI type for the data may not
be justified by the potential benefit. In such cases, it is permitted
to have a command return a simple string that contains formatted data,
however, it is mandatory for the command to be marked unstable.
however, it is mandatory for the command to use the 'x-' name prefix.
This indicates that the command is not guaranteed to be long term
stable / liable to change in future and is not following QAPI design
best practices. An example where this approach is taken is the QMP
@@ -376,207 +386,302 @@ an illustration.
User Defined Types
~~~~~~~~~~~~~~~~~~
For this example we will write the query-option-roms command, which
returns information about ROMs loaded into the option ROM space. For
more information about it, please check the "-option-rom" command-line
option.
FIXME This example needs to be redone after commit 6d32717
For each option ROM, we want to return two pieces of information: the
ROM image's file name, and its bootindex, if any. We need to create a
new QAPI type for that, as shown below::
For this example we will write the query-alarm-clock command, which returns
information about QEMU's timer alarm. For more information about it, please
check the "-clock" command-line option.
We want to return two pieces of information. The first one is the alarm clock's
name. The second one is when the next alarm will fire. The former information is
returned as a string, the latter is an integer in nanoseconds (which is not
very useful in practice, as the timer has probably already fired when the
information reaches the client).
The best way to return that data is to create a new QAPI type, as shown below::
##
# @OptionRomInfo:
# @QemuAlarmClock
#
# @filename: option ROM image file name
# QEMU alarm clock information.
#
# @bootindex: option ROM's bootindex
# @clock-name: The alarm clock method's name.
#
# Since: 9.0
# @next-deadline: The time (in nanoseconds) the next alarm will fire.
#
# Since: 1.0
##
{ 'struct': 'OptionRomInfo',
'data': { 'filename': 'str', '*bootindex': 'int' } }
{ 'type': 'QemuAlarmClock',
'data': { 'clock-name': 'str', '*next-deadline': 'int' } }
The "struct" keyword defines a new QAPI type. Its "data" member
contains the type's members. In this example our members are
"filename" and "bootindex". The latter is optional.
The "type" keyword defines a new QAPI type. Its "data" member contains the
type's members. In this example our members are the "clock-name" and the
"next-deadline" one, which is optional.
Now let's define the query-option-roms command::
Now let's define the query-alarm-clock command::
##
# @query-option-roms:
# @query-alarm-clock
#
# Query information on ROMs loaded into the option ROM space.
# Return information about QEMU's alarm clock.
#
# Returns: OptionRomInfo
# Returns a @QemuAlarmClock instance describing the alarm clock method
# being currently used by QEMU (this is usually set by the '-clock'
# command-line option).
#
# Since: 9.0
# Since: 1.0
##
{ 'command': 'query-option-roms',
'returns': ['OptionRomInfo'] }
{ 'command': 'query-alarm-clock', 'returns': 'QemuAlarmClock' }
Notice the "returns" keyword. As its name suggests, it's used to define the
data returned by a command.
Notice the syntax ['OptionRomInfo']". This should be read as "returns
a list of OptionRomInfo".
It's time to implement the qmp_query_alarm_clock() function, you can put it
in the qemu-timer.c file::
It's time to implement the qmp_query_option_roms() function. Add to
monitor/qmp-cmds.c::
OptionRomInfoList *qmp_query_option_roms(Error **errp)
QemuAlarmClock *qmp_query_alarm_clock(Error **errp)
{
OptionRomInfoList *info_list = NULL;
OptionRomInfoList **tailp = &info_list;
OptionRomInfo *info;
QemuAlarmClock *clock;
int64_t deadline;
for (int i = 0; i < nb_option_roms; i++) {
info = g_malloc0(sizeof(*info));
info->filename = g_strdup(option_rom[i].name);
info->has_bootindex = option_rom[i].bootindex >= 0;
if (info->has_bootindex) {
info->bootindex = option_rom[i].bootindex;
}
QAPI_LIST_APPEND(tailp, info);
clock = g_malloc0(sizeof(*clock));
deadline = qemu_next_alarm_deadline();
if (deadline > 0) {
clock->has_next_deadline = true;
clock->next_deadline = deadline;
}
clock->clock_name = g_strdup(alarm_timer->name);
return info_list;
return clock;
}
There are a number of things to be noticed:
1. Type OptionRomInfo is automatically generated by the QAPI framework,
its members correspond to the type's specification in the schema
file
2. Type OptionRomInfoList is also generated. It's a singly linked
list.
3. As specified in the schema file, the function returns a
OptionRomInfoList, and takes no arguments (besides the "errp" one,
which is mandatory for all QMP functions)
4. The returned object is dynamically allocated
5. All strings are dynamically allocated. This is so because QAPI also
generates a function to free its types and it cannot distinguish
between dynamically or statically allocated strings
6. Remember that "bootindex" is optional? As a non-pointer optional
member, it comes with a 'has_bootindex' member that needs to be set
1. The QemuAlarmClock type is automatically generated by the QAPI framework,
its members correspond to the type's specification in the schema file
2. As specified in the schema file, the function returns a QemuAlarmClock
instance and takes no arguments (besides the "errp" one, which is mandatory
for all QMP functions)
3. The "clock" variable (which will point to our QAPI type instance) is
allocated by the regular g_malloc0() function. Note that we chose to
initialize the memory to zero. This is recommended for all QAPI types, as
it helps avoiding bad surprises (specially with booleans)
4. Remember that "next_deadline" is optional? Non-pointer optional
members have a 'has_TYPE_NAME' member that should be properly set
by the implementation, as shown above
5. Even static strings, such as "alarm_timer->name", should be dynamically
allocated by the implementation. This is so because the QAPI also generates
a function to free its types and it cannot distinguish between dynamically
or statically allocated strings
6. You have to include "qapi/qapi-commands-misc.h" in qemu-timer.c
Time to test the new command. Build QEMU, run it as described in the "Testing"
Time to test the new command. Build qemu, run it as described in the "Testing"
section and try this::
{ "execute": "query-option-rom" }
{ "execute": "query-alarm-clock" }
{
"return": [
{
"filename": "kvmvapic.bin"
}
]
"return": {
"next-deadline": 2368219,
"clock-name": "dynticks"
}
}
The HMP command
~~~~~~~~~~~~~~~
Here's the HMP counterpart of the query-option-roms command::
Here's the HMP counterpart of the query-alarm-clock command::
void hmp_info_option_roms(Monitor *mon, const QDict *qdict)
void hmp_info_alarm_clock(Monitor *mon)
{
QemuAlarmClock *clock;
Error *err = NULL;
OptionRomInfoList *info_list, *tail;
OptionRomInfo *info;
info_list = qmp_query_option_roms(&err);
clock = qmp_query_alarm_clock(&err);
if (hmp_handle_error(mon, err)) {
return;
}
for (tail = info_list; tail; tail = tail->next) {
info = tail->value;
monitor_printf(mon, "%s", info->filename);
if (info->has_bootindex) {
monitor_printf(mon, " %" PRId64, info->bootindex);
}
monitor_printf(mon, "\n");
monitor_printf(mon, "Alarm clock method in use: '%s'\n", clock->clock_name);
if (clock->has_next_deadline) {
monitor_printf(mon, "Next alarm will fire in %" PRId64 " nanoseconds\n",
clock->next_deadline);
}
qapi_free_OptionRomInfoList(info_list);
qapi_free_QemuAlarmClock(clock);
}
It's important to notice that hmp_info_option_roms() calls
qapi_free_OptionRomInfoList() to free the data returned by
qmp_query_option_roms(). For user defined types, QAPI will generate a
qapi_free_QAPI_TYPE_NAME() function, and that's what you have to use to
free the types you define and qapi_free_QAPI_TYPE_NAMEList() for list
types (explained in the next section). If the QMP function returns a
string, then you should g_free() to free it.
It's important to notice that hmp_info_alarm_clock() calls
qapi_free_QemuAlarmClock() to free the data returned by qmp_query_alarm_clock().
For user defined types, the QAPI will generate a qapi_free_QAPI_TYPE_NAME()
function and that's what you have to use to free the types you define and
qapi_free_QAPI_TYPE_NAMEList() for list types (explained in the next section).
If the QMP call returns a string, then you should g_free() to free it.
Also note that hmp_info_option_roms() performs error handling. That's
not strictly required when you're sure the QMP function doesn't return
errors; you could instead pass it &error_abort then.
Also note that hmp_info_alarm_clock() performs error handling. That's not
strictly required if you're sure the QMP function doesn't return errors, but
it's good practice to always check for errors.
Another important detail is that HMP's "info" commands go into
hmp-commands-info.hx, not hmp-commands.hx. The entry for the "info
option-roms" follows::
Another important detail is that HMP's "info" commands don't go into the
hmp-commands.hx. Instead, they go into the info_cmds[] table, which is defined
in the monitor/misc.c file. The entry for the "info alarmclock" follows::
{
.name = "option-roms",
.args_type = "",
.params = "",
.help = "show roms",
.cmd = hmp_info_option_roms,
},
SRST
``info option-roms``
Show the option ROMs.
ERST
{
.name = "alarmclock",
.args_type = "",
.params = "",
.help = "show information about the alarm clock",
.cmd = hmp_info_alarm_clock,
},
To test this, run QEMU and type "info option-roms" in the user monitor.
To test this, run qemu and type "info alarmclock" in the user monitor.
Returning Lists
~~~~~~~~~~~~~~~
For this example, we're going to return all available methods for the timer
alarm, which is pretty much what the command-line option "-clock ?" does,
except that we're also going to inform which method is in use.
This first step is to define a new type::
##
# @TimerAlarmMethod
#
# Timer alarm method information.
#
# @method-name: The method's name.
#
# @current: true if this alarm method is currently in use, false otherwise
#
# Since: 1.0
##
{ 'type': 'TimerAlarmMethod',
'data': { 'method-name': 'str', 'current': 'bool' } }
The command will be called "query-alarm-methods", here is its schema
specification::
##
# @query-alarm-methods
#
# Returns information about available alarm methods.
#
# Returns: a list of @TimerAlarmMethod for each method
#
# Since: 1.0
##
{ 'command': 'query-alarm-methods', 'returns': ['TimerAlarmMethod'] }
Notice the syntax for returning lists "'returns': ['TimerAlarmMethod']", this
should be read as "returns a list of TimerAlarmMethod instances".
The C implementation follows::
TimerAlarmMethodList *qmp_query_alarm_methods(Error **errp)
{
TimerAlarmMethodList *method_list = NULL;
const struct qemu_alarm_timer *p;
bool current = true;
for (p = alarm_timers; p->name; p++) {
TimerAlarmMethod *value = g_malloc0(*value);
value->method_name = g_strdup(p->name);
value->current = current;
QAPI_LIST_PREPEND(method_list, value);
current = false;
}
return method_list;
}
The most important difference from the previous examples is the
TimerAlarmMethodList type, which is automatically generated by the QAPI from
the TimerAlarmMethod type.
Each list node is represented by a TimerAlarmMethodList instance. We have to
allocate it, and that's done inside the for loop: the "info" pointer points to
an allocated node. We also have to allocate the node's contents, which is
stored in its "value" member. In our example, the "value" member is a pointer
to an TimerAlarmMethod instance.
Notice that the "current" variable is used as "true" only in the first
iteration of the loop. That's because the alarm timer method in use is the
first element of the alarm_timers array. Also notice that QAPI lists are handled
by hand and we return the head of the list.
Now Build qemu, run it as explained in the "Testing" section and try our new
command::
{ "execute": "query-alarm-methods" }
{
"return": [
{
"current": false,
"method-name": "unix"
},
{
"current": true,
"method-name": "dynticks"
}
]
}
The HMP counterpart is a bit more complex than previous examples because it
has to traverse the list, it's shown below for reference::
void hmp_info_alarm_methods(Monitor *mon)
{
TimerAlarmMethodList *method_list, *method;
Error *err = NULL;
method_list = qmp_query_alarm_methods(&err);
if (hmp_handle_error(mon, err)) {
return;
}
for (method = method_list; method; method = method->next) {
monitor_printf(mon, "%c %s\n", method->value->current ? '*' : ' ',
method->value->method_name);
}
qapi_free_TimerAlarmMethodList(method_list);
}
Writing a debugging aid returning unstructured text
---------------------------------------------------
As discussed in section `Modelling data in QAPI`_, it is required that
commands expecting machine usage be using fine-grained QAPI data types.
The exception to this rule applies when the command is solely intended
as a debugging aid and allows for returning unstructured text, such as
a query command that report aspects of QEMU's internal state that are
useful only to human operators.
as a debugging aid and allows for returning unstructured text. This is
commonly needed for query commands that report aspects of QEMU's
internal state that are useful to human operators.
In this example we will consider the existing QMP command
``x-query-roms`` in qapi/machine.json. It has no parameters and
returns a ``HumanReadableText``::
In this example we will consider a simplified variant of the HMP
command ``info roms``. Following the earlier rules, this command will
need to live under the ``x-`` name prefix, so its QMP implementation
will be called ``x-query-roms``. It will have no parameters and will
return a single text string::
{ 'struct': 'HumanReadableText',
'data': { 'human-readable-text': 'str' } }
##
# @x-query-roms:
#
# Query information on the registered ROMS
#
# Features:
#
# @unstable: This command is meant for debugging.
#
# Returns: registered ROMs
#
# Since: 6.2
##
{ 'command': 'x-query-roms',
'returns': 'HumanReadableText',
'features': [ 'unstable' ] }
'returns': 'HumanReadableText' }
The ``HumanReadableText`` struct is defined in qapi/common.json as a
struct with a string member. It is intended to be used for all
commands that are returning unstructured text targeted at
humans. These should all have feature 'unstable'. Note that the
feature's documentation states why the command is unstable. We
commonly use a ``x-`` command name prefix to make lack of stability
obvious to human users.
The ``HumanReadableText`` struct is intended to be used for all
commands, under the ``x-`` name prefix that are returning unstructured
text targeted at humans. It should never be used for commands outside
the ``x-`` name prefix, as those should be using structured QAPI types.
Implementing the QMP command
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The QMP implementation will typically involve creating a ``GString``
object and printing formatted data into it, like this::
object and printing formatted data into it::
HumanReadableText *qmp_x_query_roms(Error **errp)
{
@@ -593,9 +698,6 @@ object and printing formatted data into it, like this::
return human_readable_text_from_str(buf);
}
The actual implementation emits more information. You can find it in
hw/core/loader.c.
Implementing the HMP command
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -604,7 +706,7 @@ Now that the QMP command is in place, we can also make it available in
the human monitor (HMP) as shown in previous examples. The HMP
implementations will all look fairly similar, as all they need do is
invoke the QMP command and then print the resulting text or error
message. Here's an implementation of the "info roms" HMP command::
message. Here's the implementation of the "info roms" HMP command::
void hmp_info_roms(Monitor *mon, const QDict *qdict)
{
@@ -644,5 +746,3 @@ field NULL::
.help = "show roms",
.cmd_info_hrt = qmp_x_query_roms,
},
This is how the actual HMP command is done.

Some files were not shown because too many files have changed in this diff Show More