Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
e2f6827b05
@ -32,7 +32,6 @@ windows_msys2_task:
|
||||
mingw-w64-x86_64-libgcrypt
|
||||
mingw-w64-x86_64-libpng
|
||||
mingw-w64-x86_64-libssh
|
||||
mingw-w64-x86_64-libxml2
|
||||
mingw-w64-x86_64-snappy
|
||||
mingw-w64-x86_64-libusb
|
||||
mingw-w64-x86_64-usbredir
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -17,3 +17,4 @@ GTAGS
|
||||
*.depend_raw
|
||||
*.swp
|
||||
*.patch
|
||||
*.gcov
|
||||
|
@ -473,33 +473,6 @@ tsan-build:
|
||||
TARGETS: x86_64-softmmu ppc64-softmmu riscv64-softmmu x86_64-linux-user
|
||||
MAKE_CHECK_ARGS: bench V=1
|
||||
|
||||
# These targets are on the way out
|
||||
build-deprecated:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
job: amd64-debian-user-cross-container
|
||||
variables:
|
||||
IMAGE: debian-all-test-cross
|
||||
CONFIGURE_ARGS: --disable-tools
|
||||
MAKE_CHECK_ARGS: build-tcg
|
||||
TARGETS: ppc64abi32-linux-user
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
# We split the check-tcg step as test failures are expected but we still
|
||||
# want to catch the build breaking.
|
||||
check-deprecated:
|
||||
extends: .native_test_job_template
|
||||
needs:
|
||||
- job: build-deprecated
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: debian-all-test-cross
|
||||
MAKE_CHECK_ARGS: check-tcg
|
||||
allow_failure: true
|
||||
|
||||
# gprof/gcov are GCC features
|
||||
build-gprof-gcov:
|
||||
extends: .native_build_job_template
|
||||
|
@ -11,6 +11,6 @@ MAKE='/usr/local/bin/gmake'
|
||||
NINJA='/usr/local/bin/ninja'
|
||||
PACKAGING_COMMAND='pkg'
|
||||
PIP3='/usr/local/bin/pip-3.8'
|
||||
PKGS='alsa-lib bash bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage ctags curl cyrus-sasl dbus diffutils dtc gettext git glib gmake gnutls gsed gtk3 libepoxy libffi libgcrypt libjpeg-turbo libnfs libspice-server libssh libtasn1 libxml2 llvm lttng-ust lzo2 meson ncurses nettle ninja opencv p5-Test-Harness perl5 pixman pkgconf png py38-numpy py38-pillow py38-pip py38-sphinx py38-sphinx_rtd_theme py38-virtualenv py38-yaml python3 rpm2cpio sdl2 sdl2_image snappy spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd'
|
||||
PKGS='alsa-lib bash bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage ctags curl cyrus-sasl dbus diffutils dtc fusefs-libs3 gettext git glib gmake gnutls gsed gtk3 libepoxy libffi libgcrypt libjpeg-turbo libnfs libspice-server libssh libtasn1 llvm lzo2 meson ncurses nettle ninja opencv p5-Test-Harness perl5 pixman pkgconf png py38-numpy py38-pillow py38-pip py38-sphinx py38-sphinx_rtd_theme py38-virtualenv py38-yaml python3 rpm2cpio sdl2 sdl2_image snappy spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd'
|
||||
PYPI_PKGS=''
|
||||
PYTHON='/usr/local/bin/python3'
|
||||
|
@ -11,6 +11,6 @@ MAKE='/usr/local/bin/gmake'
|
||||
NINJA='/usr/local/bin/ninja'
|
||||
PACKAGING_COMMAND='pkg'
|
||||
PIP3='/usr/local/bin/pip-3.8'
|
||||
PKGS='alsa-lib bash bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage ctags curl cyrus-sasl dbus diffutils dtc gettext git glib gmake gnutls gsed gtk3 libepoxy libffi libgcrypt libjpeg-turbo libnfs libspice-server libssh libtasn1 libxml2 llvm lttng-ust lzo2 meson ncurses nettle ninja opencv p5-Test-Harness perl5 pixman pkgconf png py38-numpy py38-pillow py38-pip py38-sphinx py38-sphinx_rtd_theme py38-virtualenv py38-yaml python3 rpm2cpio sdl2 sdl2_image snappy spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd'
|
||||
PKGS='alsa-lib bash bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage ctags curl cyrus-sasl dbus diffutils dtc fusefs-libs3 gettext git glib gmake gnutls gsed gtk3 libepoxy libffi libgcrypt libjpeg-turbo libnfs libspice-server libssh libtasn1 llvm lzo2 meson ncurses nettle ninja opencv p5-Test-Harness perl5 pixman pkgconf png py38-numpy py38-pillow py38-pip py38-sphinx py38-sphinx_rtd_theme py38-virtualenv py38-yaml python3 rpm2cpio sdl2 sdl2_image snappy spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd'
|
||||
PYPI_PKGS=''
|
||||
PYTHON='/usr/local/bin/python3'
|
||||
|
@ -11,6 +11,6 @@ MAKE='/usr/local/bin/gmake'
|
||||
NINJA='/usr/local/bin/ninja'
|
||||
PACKAGING_COMMAND='brew'
|
||||
PIP3='/usr/local/bin/pip3'
|
||||
PKGS='bash bc bzip2 capstone ccache cpanminus ctags curl dbus diffutils dtc gcovr gettext git glib gnu-sed gnutls gtk+3 jemalloc jpeg-turbo libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb libxml2 llvm lzo make meson ncurses nettle ninja perl pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy sparse spice-protocol tesseract texinfo usbredir vde vte3 zlib zstd'
|
||||
PKGS='bash bc bzip2 capstone ccache cpanminus ctags curl dbus diffutils dtc gcovr gettext git glib gnu-sed gnutls gtk+3 jemalloc jpeg-turbo libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make meson ncurses nettle ninja perl pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy sparse spice-protocol tesseract texinfo usbredir vde vte3 zlib zstd'
|
||||
PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme virtualenv'
|
||||
PYTHON='/usr/local/bin/python3'
|
||||
|
@ -14,7 +14,7 @@
|
||||
- make -j$(expr $(nproc) + 1) all check-build $MAKE_CHECK_ARGS
|
||||
- if grep -q "EXESUF=.exe" config-host.mak;
|
||||
then make installer;
|
||||
version="$(git describe --match v[0-9]*)";
|
||||
version="$(git describe --match v[0-9]* 2>/dev/null || git rev-parse --short HEAD)";
|
||||
mv -v qemu-setup*.exe qemu-setup-${version}.exe;
|
||||
fi
|
||||
|
||||
|
@ -44,7 +44,6 @@ msys2-64bit:
|
||||
mingw-w64-x86_64-libssh
|
||||
mingw-w64-x86_64-libtasn1
|
||||
mingw-w64-x86_64-libusb
|
||||
mingw-w64-x86_64-libxml2
|
||||
mingw-w64-x86_64-nettle
|
||||
mingw-w64-x86_64-ninja
|
||||
mingw-w64-x86_64-pixman
|
||||
@ -80,7 +79,6 @@ msys2-32bit:
|
||||
mingw-w64-i686-libssh
|
||||
mingw-w64-i686-libtasn1
|
||||
mingw-w64-i686-libusb
|
||||
mingw-w64-i686-libxml2
|
||||
mingw-w64-i686-lzo2
|
||||
mingw-w64-i686-ninja
|
||||
mingw-w64-i686-pixman
|
||||
|
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -66,4 +66,4 @@
|
||||
url = https://gitlab.com/qemu-project/vbootrom.git
|
||||
[submodule "tests/lcitool/libvirt-ci"]
|
||||
path = tests/lcitool/libvirt-ci
|
||||
url = http://gitlab.com/libvirt/libvirt-ci
|
||||
url = https://gitlab.com/libvirt/libvirt-ci.git
|
||||
|
18
MAINTAINERS
18
MAINTAINERS
@ -286,6 +286,13 @@ F: include/hw/riscv/
|
||||
F: linux-user/host/riscv32/
|
||||
F: linux-user/host/riscv64/
|
||||
|
||||
RISC-V XVentanaCondOps extension
|
||||
M: Philipp Tomsich <philipp.tomsich@vrull.eu>
|
||||
L: qemu-riscv@nongnu.org
|
||||
S: Supported
|
||||
F: target/riscv/XVentanaCondOps.decode
|
||||
F: target/riscv/insn_trans/trans_xventanacondops.c.inc
|
||||
|
||||
RENESAS RX CPUs
|
||||
R: Yoshinori Sato <ysato@users.sourceforge.jp>
|
||||
S: Orphan
|
||||
@ -408,7 +415,7 @@ M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
M: Marcelo Tosatti <mtosatti@redhat.com>
|
||||
L: kvm@vger.kernel.org
|
||||
S: Supported
|
||||
F: docs/amd-memory-encryption.txt
|
||||
F: docs/system/i386/amd-memory-encryption.rst
|
||||
F: docs/system/i386/sgx.rst
|
||||
F: target/i386/kvm/
|
||||
F: target/i386/sev*
|
||||
@ -818,7 +825,6 @@ F: docs/system/arm/palm.rst
|
||||
|
||||
Raspberry Pi
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
R: Andrew Baumann <Andrew.Baumann@microsoft.com>
|
||||
R: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Odd Fixes
|
||||
@ -958,6 +964,12 @@ F: hw/display/dpcd.c
|
||||
F: include/hw/display/dpcd.h
|
||||
F: docs/system/arm/xlnx-versal-virt.rst
|
||||
|
||||
Xilinx Versal OSPI
|
||||
M: Francisco Iglesias <francisco.iglesias@xilinx.com>
|
||||
S: Maintained
|
||||
F: hw/ssi/xlnx-versal-ospi.c
|
||||
F: include/hw/ssi/xlnx-versal-ospi.h
|
||||
|
||||
ARM ACPI Subsystem
|
||||
M: Shannon Zhao <shannon.zhaosl@gmail.com>
|
||||
L: qemu-arm@nongnu.org
|
||||
@ -3181,6 +3193,7 @@ R: Kyle Evans <kevans@freebsd.org>
|
||||
S: Maintained
|
||||
F: bsd-user/
|
||||
F: configs/targets/*-bsd-user.mak
|
||||
F: tests/vm/*bsd
|
||||
T: git https://github.com/qemu-bsd-user/qemu-bsd-user bsd-user-rebase-3.1
|
||||
|
||||
Linux user
|
||||
@ -3579,6 +3592,7 @@ F: .travis.yml
|
||||
F: scripts/ci/
|
||||
F: tests/docker/
|
||||
F: tests/vm/
|
||||
F: tests/lcitool/
|
||||
F: scripts/archive-source.sh
|
||||
W: https://gitlab.com/qemu-project/qemu/pipelines
|
||||
W: https://travis-ci.org/qemu/qemu
|
||||
|
3
Makefile
3
Makefile
@ -206,7 +206,8 @@ recurse-clean: $(addsuffix /clean, $(ROM_DIRS))
|
||||
clean: recurse-clean
|
||||
-$(quiet-@)test -f build.ninja && $(NINJA) $(NINJAFLAGS) -t clean || :
|
||||
-$(quiet-@)test -f build.ninja && $(NINJA) $(NINJAFLAGS) clean-ctlist || :
|
||||
find . \( -name '*.so' -o -name '*.dll' -o -name '*.[oda]' \) -type f \
|
||||
find . \( -name '*.so' -o -name '*.dll' -o \
|
||||
-name '*.[oda]' -o -name '*.gcno' \) -type f \
|
||||
! -path ./roms/edk2/ArmPkg/Library/GccLto/liblto-aarch64.a \
|
||||
! -path ./roms/edk2/ArmPkg/Library/GccLto/liblto-arm.a \
|
||||
-exec rm {} +
|
||||
|
@ -13,14 +13,6 @@
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
static void atomic_trace_rmw_pre(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi)
|
||||
{
|
||||
CPUState *cpu = env_cpu(env);
|
||||
|
||||
trace_guest_rmw_before_exec(cpu, addr, oi);
|
||||
}
|
||||
|
||||
static void atomic_trace_rmw_post(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi)
|
||||
{
|
||||
@ -28,24 +20,12 @@ static void atomic_trace_rmw_post(CPUArchState *env, target_ulong addr,
|
||||
}
|
||||
|
||||
#if HAVE_ATOMIC128
|
||||
static void atomic_trace_ld_pre(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi)
|
||||
{
|
||||
trace_guest_ld_before_exec(env_cpu(env), addr, oi);
|
||||
}
|
||||
|
||||
static void atomic_trace_ld_post(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi)
|
||||
{
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R);
|
||||
}
|
||||
|
||||
static void atomic_trace_st_pre(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi)
|
||||
{
|
||||
trace_guest_st_before_exec(env_cpu(env), addr, oi);
|
||||
}
|
||||
|
||||
static void atomic_trace_st_post(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi)
|
||||
{
|
||||
|
@ -77,7 +77,6 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
|
||||
PAGE_READ | PAGE_WRITE, retaddr);
|
||||
DATA_TYPE ret;
|
||||
|
||||
atomic_trace_rmw_pre(env, addr, oi);
|
||||
#if DATA_SIZE == 16
|
||||
ret = atomic16_cmpxchg(haddr, cmpv, newv);
|
||||
#else
|
||||
@ -97,7 +96,6 @@ ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr,
|
||||
PAGE_READ, retaddr);
|
||||
DATA_TYPE val;
|
||||
|
||||
atomic_trace_ld_pre(env, addr, oi);
|
||||
val = atomic16_read(haddr);
|
||||
ATOMIC_MMU_CLEANUP;
|
||||
atomic_trace_ld_post(env, addr, oi);
|
||||
@ -110,7 +108,6 @@ void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
|
||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
||||
PAGE_WRITE, retaddr);
|
||||
|
||||
atomic_trace_st_pre(env, addr, oi);
|
||||
atomic16_set(haddr, val);
|
||||
ATOMIC_MMU_CLEANUP;
|
||||
atomic_trace_st_post(env, addr, oi);
|
||||
@ -124,7 +121,6 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
|
||||
PAGE_READ | PAGE_WRITE, retaddr);
|
||||
DATA_TYPE ret;
|
||||
|
||||
atomic_trace_rmw_pre(env, addr, oi);
|
||||
ret = qatomic_xchg__nocheck(haddr, val);
|
||||
ATOMIC_MMU_CLEANUP;
|
||||
atomic_trace_rmw_post(env, addr, oi);
|
||||
@ -138,7 +134,6 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
|
||||
PAGE_READ | PAGE_WRITE, retaddr); \
|
||||
DATA_TYPE ret; \
|
||||
atomic_trace_rmw_pre(env, addr, oi); \
|
||||
ret = qatomic_##X(haddr, val); \
|
||||
ATOMIC_MMU_CLEANUP; \
|
||||
atomic_trace_rmw_post(env, addr, oi); \
|
||||
@ -171,7 +166,6 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
||||
XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
|
||||
PAGE_READ | PAGE_WRITE, retaddr); \
|
||||
XDATA_TYPE cmp, old, new, val = xval; \
|
||||
atomic_trace_rmw_pre(env, addr, oi); \
|
||||
smp_mb(); \
|
||||
cmp = qatomic_read__nocheck(haddr); \
|
||||
do { \
|
||||
@ -216,7 +210,6 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
|
||||
PAGE_READ | PAGE_WRITE, retaddr);
|
||||
DATA_TYPE ret;
|
||||
|
||||
atomic_trace_rmw_pre(env, addr, oi);
|
||||
#if DATA_SIZE == 16
|
||||
ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv));
|
||||
#else
|
||||
@ -236,7 +229,6 @@ ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr,
|
||||
PAGE_READ, retaddr);
|
||||
DATA_TYPE val;
|
||||
|
||||
atomic_trace_ld_pre(env, addr, oi);
|
||||
val = atomic16_read(haddr);
|
||||
ATOMIC_MMU_CLEANUP;
|
||||
atomic_trace_ld_post(env, addr, oi);
|
||||
@ -249,7 +241,6 @@ void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
|
||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
||||
PAGE_WRITE, retaddr);
|
||||
|
||||
atomic_trace_st_pre(env, addr, oi);
|
||||
val = BSWAP(val);
|
||||
atomic16_set(haddr, val);
|
||||
ATOMIC_MMU_CLEANUP;
|
||||
@ -264,7 +255,6 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
|
||||
PAGE_READ | PAGE_WRITE, retaddr);
|
||||
ABI_TYPE ret;
|
||||
|
||||
atomic_trace_rmw_pre(env, addr, oi);
|
||||
ret = qatomic_xchg__nocheck(haddr, BSWAP(val));
|
||||
ATOMIC_MMU_CLEANUP;
|
||||
atomic_trace_rmw_post(env, addr, oi);
|
||||
@ -278,7 +268,6 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
|
||||
PAGE_READ | PAGE_WRITE, retaddr); \
|
||||
DATA_TYPE ret; \
|
||||
atomic_trace_rmw_pre(env, addr, oi); \
|
||||
ret = qatomic_##X(haddr, BSWAP(val)); \
|
||||
ATOMIC_MMU_CLEANUP; \
|
||||
atomic_trace_rmw_post(env, addr, oi); \
|
||||
@ -308,7 +297,6 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
||||
XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
|
||||
PAGE_READ | PAGE_WRITE, retaddr); \
|
||||
XDATA_TYPE ldo, ldn, old, new, val = xval; \
|
||||
atomic_trace_rmw_pre(env, addr, oi); \
|
||||
smp_mb(); \
|
||||
ldn = qatomic_read__nocheck(haddr); \
|
||||
do { \
|
||||
|
@ -660,7 +660,8 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
|
||||
if (replay_has_exception()
|
||||
&& cpu_neg(cpu)->icount_decr.u16.low + cpu->icount_extra == 0) {
|
||||
/* Execute just one insn to trigger exception pending in the log */
|
||||
cpu->cflags_next_tb = (curr_cflags(cpu) & ~CF_USE_ICOUNT) | 1;
|
||||
cpu->cflags_next_tb = (curr_cflags(cpu) & ~CF_USE_ICOUNT)
|
||||
| CF_NOIRQ | 1;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
|
@ -783,6 +783,15 @@ static void tlb_flush_range_by_mmuidx_async_0(CPUState *cpu,
|
||||
}
|
||||
qemu_spin_unlock(&env_tlb(env)->c.lock);
|
||||
|
||||
/*
|
||||
* If the length is larger than the jump cache size, then it will take
|
||||
* longer to clear each entry individually than it will to clear it all.
|
||||
*/
|
||||
if (d.len >= (TARGET_PAGE_SIZE * TB_JMP_CACHE_SIZE)) {
|
||||
cpu_tb_jmp_cache_clear(cpu);
|
||||
return;
|
||||
}
|
||||
|
||||
for (target_ulong i = 0; i < d.len; i += TARGET_PAGE_SIZE) {
|
||||
tb_flush_jmp_cache(cpu, d.addr + i);
|
||||
}
|
||||
@ -2140,7 +2149,6 @@ static inline uint64_t cpu_load_helper(CPUArchState *env, abi_ptr addr,
|
||||
{
|
||||
uint64_t ret;
|
||||
|
||||
trace_guest_ld_before_exec(env_cpu(env), addr, oi);
|
||||
ret = full_load(env, addr, oi, retaddr);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R);
|
||||
return ret;
|
||||
@ -2487,7 +2495,6 @@ static inline void cpu_store_helper(CPUArchState *env, target_ulong addr,
|
||||
uint64_t val, MemOpIdx oi, uintptr_t ra,
|
||||
FullStoreHelper *full_store)
|
||||
{
|
||||
trace_guest_st_before_exec(env_cpu(env), addr, oi);
|
||||
full_store(env, addr, val, oi, ra);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W);
|
||||
}
|
||||
|
@ -854,10 +854,20 @@ static void plugin_gen_inject(const struct qemu_plugin_tb *plugin_tb)
|
||||
|
||||
bool plugin_gen_tb_start(CPUState *cpu, const TranslationBlock *tb, bool mem_only)
|
||||
{
|
||||
struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
|
||||
bool ret = false;
|
||||
|
||||
if (test_bit(QEMU_PLUGIN_EV_VCPU_TB_TRANS, cpu->plugin_mask)) {
|
||||
struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
|
||||
int i;
|
||||
|
||||
/* reset callbacks */
|
||||
for (i = 0; i < PLUGIN_N_CB_SUBTYPES; i++) {
|
||||
if (ptb->cbs[i]) {
|
||||
g_array_set_size(ptb->cbs[i], 0);
|
||||
}
|
||||
}
|
||||
ptb->n = 0;
|
||||
|
||||
ret = true;
|
||||
|
||||
ptb->vaddr = tb->pc;
|
||||
@ -868,6 +878,9 @@ bool plugin_gen_tb_start(CPUState *cpu, const TranslationBlock *tb, bool mem_onl
|
||||
|
||||
plugin_gen_empty_callback(PLUGIN_GEN_FROM_TB);
|
||||
}
|
||||
|
||||
tcg_ctx->plugin_insn = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -904,23 +917,19 @@ void plugin_gen_insn_end(void)
|
||||
plugin_gen_empty_callback(PLUGIN_GEN_AFTER_INSN);
|
||||
}
|
||||
|
||||
/*
|
||||
* There are cases where we never get to finalise a translation - for
|
||||
* example a page fault during translation. As a result we shouldn't
|
||||
* do any clean-up here and make sure things are reset in
|
||||
* plugin_gen_tb_start.
|
||||
*/
|
||||
void plugin_gen_tb_end(CPUState *cpu)
|
||||
{
|
||||
struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
|
||||
int i;
|
||||
|
||||
/* collect instrumentation requests */
|
||||
qemu_plugin_tb_trans_cb(cpu, ptb);
|
||||
|
||||
/* inject the instrumentation at the appropriate places */
|
||||
plugin_gen_inject(ptb);
|
||||
|
||||
/* clean up */
|
||||
for (i = 0; i < PLUGIN_N_CB_SUBTYPES; i++) {
|
||||
if (ptb->cbs[i]) {
|
||||
g_array_set_size(ptb->cbs[i], 0);
|
||||
}
|
||||
}
|
||||
ptb->n = 0;
|
||||
tcg_ctx->plugin_insn = NULL;
|
||||
}
|
||||
|
@ -250,7 +250,6 @@ uint8_t cpu_ldb_mmu(CPUArchState *env, abi_ptr addr,
|
||||
uint8_t ret;
|
||||
|
||||
validate_memop(oi, MO_UB);
|
||||
trace_guest_ld_before_exec(env_cpu(env), addr, oi);
|
||||
haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_LOAD);
|
||||
ret = ldub_p(haddr);
|
||||
clear_helper_retaddr();
|
||||
@ -265,7 +264,6 @@ uint16_t cpu_ldw_be_mmu(CPUArchState *env, abi_ptr addr,
|
||||
uint16_t ret;
|
||||
|
||||
validate_memop(oi, MO_BEUW);
|
||||
trace_guest_ld_before_exec(env_cpu(env), addr, oi);
|
||||
haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_LOAD);
|
||||
ret = lduw_be_p(haddr);
|
||||
clear_helper_retaddr();
|
||||
@ -280,7 +278,6 @@ uint32_t cpu_ldl_be_mmu(CPUArchState *env, abi_ptr addr,
|
||||
uint32_t ret;
|
||||
|
||||
validate_memop(oi, MO_BEUL);
|
||||
trace_guest_ld_before_exec(env_cpu(env), addr, oi);
|
||||
haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_LOAD);
|
||||
ret = ldl_be_p(haddr);
|
||||
clear_helper_retaddr();
|
||||
@ -295,7 +292,6 @@ uint64_t cpu_ldq_be_mmu(CPUArchState *env, abi_ptr addr,
|
||||
uint64_t ret;
|
||||
|
||||
validate_memop(oi, MO_BEUQ);
|
||||
trace_guest_ld_before_exec(env_cpu(env), addr, oi);
|
||||
haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_LOAD);
|
||||
ret = ldq_be_p(haddr);
|
||||
clear_helper_retaddr();
|
||||
@ -310,7 +306,6 @@ uint16_t cpu_ldw_le_mmu(CPUArchState *env, abi_ptr addr,
|
||||
uint16_t ret;
|
||||
|
||||
validate_memop(oi, MO_LEUW);
|
||||
trace_guest_ld_before_exec(env_cpu(env), addr, oi);
|
||||
haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_LOAD);
|
||||
ret = lduw_le_p(haddr);
|
||||
clear_helper_retaddr();
|
||||
@ -325,7 +320,6 @@ uint32_t cpu_ldl_le_mmu(CPUArchState *env, abi_ptr addr,
|
||||
uint32_t ret;
|
||||
|
||||
validate_memop(oi, MO_LEUL);
|
||||
trace_guest_ld_before_exec(env_cpu(env), addr, oi);
|
||||
haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_LOAD);
|
||||
ret = ldl_le_p(haddr);
|
||||
clear_helper_retaddr();
|
||||
@ -340,7 +334,6 @@ uint64_t cpu_ldq_le_mmu(CPUArchState *env, abi_ptr addr,
|
||||
uint64_t ret;
|
||||
|
||||
validate_memop(oi, MO_LEUQ);
|
||||
trace_guest_ld_before_exec(env_cpu(env), addr, oi);
|
||||
haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_LOAD);
|
||||
ret = ldq_le_p(haddr);
|
||||
clear_helper_retaddr();
|
||||
@ -354,7 +347,6 @@ void cpu_stb_mmu(CPUArchState *env, abi_ptr addr, uint8_t val,
|
||||
void *haddr;
|
||||
|
||||
validate_memop(oi, MO_UB);
|
||||
trace_guest_st_before_exec(env_cpu(env), addr, oi);
|
||||
haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE);
|
||||
stb_p(haddr, val);
|
||||
clear_helper_retaddr();
|
||||
@ -367,7 +359,6 @@ void cpu_stw_be_mmu(CPUArchState *env, abi_ptr addr, uint16_t val,
|
||||
void *haddr;
|
||||
|
||||
validate_memop(oi, MO_BEUW);
|
||||
trace_guest_st_before_exec(env_cpu(env), addr, oi);
|
||||
haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE);
|
||||
stw_be_p(haddr, val);
|
||||
clear_helper_retaddr();
|
||||
@ -380,7 +371,6 @@ void cpu_stl_be_mmu(CPUArchState *env, abi_ptr addr, uint32_t val,
|
||||
void *haddr;
|
||||
|
||||
validate_memop(oi, MO_BEUL);
|
||||
trace_guest_st_before_exec(env_cpu(env), addr, oi);
|
||||
haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE);
|
||||
stl_be_p(haddr, val);
|
||||
clear_helper_retaddr();
|
||||
@ -393,7 +383,6 @@ void cpu_stq_be_mmu(CPUArchState *env, abi_ptr addr, uint64_t val,
|
||||
void *haddr;
|
||||
|
||||
validate_memop(oi, MO_BEUQ);
|
||||
trace_guest_st_before_exec(env_cpu(env), addr, oi);
|
||||
haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE);
|
||||
stq_be_p(haddr, val);
|
||||
clear_helper_retaddr();
|
||||
@ -406,7 +395,6 @@ void cpu_stw_le_mmu(CPUArchState *env, abi_ptr addr, uint16_t val,
|
||||
void *haddr;
|
||||
|
||||
validate_memop(oi, MO_LEUW);
|
||||
trace_guest_st_before_exec(env_cpu(env), addr, oi);
|
||||
haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE);
|
||||
stw_le_p(haddr, val);
|
||||
clear_helper_retaddr();
|
||||
@ -419,7 +407,6 @@ void cpu_stl_le_mmu(CPUArchState *env, abi_ptr addr, uint32_t val,
|
||||
void *haddr;
|
||||
|
||||
validate_memop(oi, MO_LEUL);
|
||||
trace_guest_st_before_exec(env_cpu(env), addr, oi);
|
||||
haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE);
|
||||
stl_le_p(haddr, val);
|
||||
clear_helper_retaddr();
|
||||
@ -432,7 +419,6 @@ void cpu_stq_le_mmu(CPUArchState *env, abi_ptr addr, uint64_t val,
|
||||
void *haddr;
|
||||
|
||||
validate_memop(oi, MO_LEUQ);
|
||||
trace_guest_st_before_exec(env_cpu(env), addr, oi);
|
||||
haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE);
|
||||
stq_le_p(haddr, val);
|
||||
clear_helper_retaddr();
|
||||
|
4
block.c
4
block.c
@ -3341,6 +3341,8 @@ int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
|
||||
int ret;
|
||||
Transaction *tran = tran_new();
|
||||
|
||||
bdrv_drained_begin(bs);
|
||||
|
||||
ret = bdrv_set_backing_noperm(bs, backing_hd, tran, errp);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
@ -3350,6 +3352,8 @@ int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
|
||||
out:
|
||||
tran_finalize(tran, ret);
|
||||
|
||||
bdrv_drained_end(bs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -190,6 +190,7 @@ static void blk_root_activate(BdrvChild *child, Error **errp)
|
||||
{
|
||||
BlockBackend *blk = child->opaque;
|
||||
Error *local_err = NULL;
|
||||
uint64_t saved_shared_perm;
|
||||
|
||||
if (!blk->disable_perm) {
|
||||
return;
|
||||
@ -197,12 +198,22 @@ static void blk_root_activate(BdrvChild *child, Error **errp)
|
||||
|
||||
blk->disable_perm = false;
|
||||
|
||||
/*
|
||||
* blk->shared_perm contains the permissions we want to share once
|
||||
* migration is really completely done. For now, we need to share
|
||||
* all; but we also need to retain blk->shared_perm, which is
|
||||
* overwritten by a successful blk_set_perm() call. Save it and
|
||||
* restore it below.
|
||||
*/
|
||||
saved_shared_perm = blk->shared_perm;
|
||||
|
||||
blk_set_perm(blk, blk->perm, BLK_PERM_ALL, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
blk->disable_perm = true;
|
||||
return;
|
||||
}
|
||||
blk->shared_perm = saved_shared_perm;
|
||||
|
||||
if (runstate_check(RUN_STATE_INMIGRATE)) {
|
||||
/* Activation can happen when migration process is still active, for
|
||||
|
@ -625,11 +625,33 @@ static void fuse_fallocate(fuse_req_t req, fuse_ino_t inode, int mode,
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FALLOCATE_PUNCH_HOLE
|
||||
if (mode & FALLOC_FL_KEEP_SIZE) {
|
||||
length = MIN(length, blk_len - offset);
|
||||
}
|
||||
#endif /* CONFIG_FALLOCATE_PUNCH_HOLE */
|
||||
|
||||
if (mode & FALLOC_FL_PUNCH_HOLE) {
|
||||
if (!mode) {
|
||||
/* We can only fallocate at the EOF with a truncate */
|
||||
if (offset < blk_len) {
|
||||
fuse_reply_err(req, EOPNOTSUPP);
|
||||
return;
|
||||
}
|
||||
|
||||
if (offset > blk_len) {
|
||||
/* No preallocation needed here */
|
||||
ret = fuse_do_truncate(exp, offset, true, PREALLOC_MODE_OFF);
|
||||
if (ret < 0) {
|
||||
fuse_reply_err(req, -ret);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ret = fuse_do_truncate(exp, offset + length, true,
|
||||
PREALLOC_MODE_FALLOC);
|
||||
}
|
||||
#ifdef CONFIG_FALLOCATE_PUNCH_HOLE
|
||||
else if (mode & FALLOC_FL_PUNCH_HOLE) {
|
||||
if (!(mode & FALLOC_FL_KEEP_SIZE)) {
|
||||
fuse_reply_err(req, EINVAL);
|
||||
return;
|
||||
@ -643,6 +665,7 @@ static void fuse_fallocate(fuse_req_t req, fuse_ino_t inode, int mode,
|
||||
length -= size;
|
||||
} while (ret == 0 && length > 0);
|
||||
}
|
||||
#endif /* CONFIG_FALLOCATE_PUNCH_HOLE */
|
||||
#ifdef CONFIG_FALLOCATE_ZERO_RANGE
|
||||
else if (mode & FALLOC_FL_ZERO_RANGE) {
|
||||
if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + length > blk_len) {
|
||||
@ -665,25 +688,7 @@ static void fuse_fallocate(fuse_req_t req, fuse_ino_t inode, int mode,
|
||||
} while (ret == 0 && length > 0);
|
||||
}
|
||||
#endif /* CONFIG_FALLOCATE_ZERO_RANGE */
|
||||
else if (!mode) {
|
||||
/* We can only fallocate at the EOF with a truncate */
|
||||
if (offset < blk_len) {
|
||||
fuse_reply_err(req, EOPNOTSUPP);
|
||||
return;
|
||||
}
|
||||
|
||||
if (offset > blk_len) {
|
||||
/* No preallocation needed here */
|
||||
ret = fuse_do_truncate(exp, offset, true, PREALLOC_MODE_OFF);
|
||||
if (ret < 0) {
|
||||
fuse_reply_err(req, -ret);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ret = fuse_do_truncate(exp, offset + length, true,
|
||||
PREALLOC_MODE_FALLOC);
|
||||
} else {
|
||||
else {
|
||||
ret = -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
|
@ -172,6 +172,7 @@ vu_blk_discard_write_zeroes(VuBlkExport *vexp, struct iovec *iov,
|
||||
return VIRTIO_BLK_S_IOERR;
|
||||
}
|
||||
|
||||
/* Called with server refcount increased, must decrease before returning */
|
||||
static void coroutine_fn vu_blk_virtio_process_req(void *opaque)
|
||||
{
|
||||
VuBlkReq *req = opaque;
|
||||
@ -286,10 +287,12 @@ static void coroutine_fn vu_blk_virtio_process_req(void *opaque)
|
||||
}
|
||||
|
||||
vu_blk_req_complete(req);
|
||||
vhost_user_server_unref(server);
|
||||
return;
|
||||
|
||||
err:
|
||||
free(req);
|
||||
vhost_user_server_unref(server);
|
||||
}
|
||||
|
||||
static void vu_blk_process_vq(VuDev *vu_dev, int idx)
|
||||
@ -310,6 +313,8 @@ static void vu_blk_process_vq(VuDev *vu_dev, int idx)
|
||||
|
||||
Coroutine *co =
|
||||
qemu_coroutine_create(vu_blk_virtio_process_req, req);
|
||||
|
||||
vhost_user_server_ref(server);
|
||||
qemu_coroutine_enter(co);
|
||||
}
|
||||
}
|
||||
|
@ -2497,8 +2497,12 @@ static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
|
||||
* non-protocol nodes, and then it is never used. However, filling
|
||||
* the cache requires an RCU update, so double check here to avoid
|
||||
* such an update if possible.
|
||||
*
|
||||
* Check want_zero, because we only want to update the cache when we
|
||||
* have accurate information about what is zero and what is data.
|
||||
*/
|
||||
if (ret == (BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID) &&
|
||||
if (want_zero &&
|
||||
ret == (BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID) &&
|
||||
QLIST_EMPTY(&bs->children))
|
||||
{
|
||||
/*
|
||||
|
@ -58,8 +58,7 @@ block_ss.add(when: 'CONFIG_QED', if_true: files(
|
||||
'qed-table.c',
|
||||
'qed.c',
|
||||
))
|
||||
block_ss.add(when: [libxml2, 'CONFIG_PARALLELS'],
|
||||
if_true: files('parallels.c', 'parallels-ext.c'))
|
||||
block_ss.add(when: 'CONFIG_PARALLELS', if_true: files('parallels.c', 'parallels-ext.c'))
|
||||
block_ss.add(when: 'CONFIG_WIN32', if_true: files('file-win32.c', 'win32-aio.c'))
|
||||
block_ss.add(when: 'CONFIG_POSIX', if_true: [files('file-posix.c'), coref, iokit])
|
||||
block_ss.add(when: libiscsi, if_true: files('iscsi-opts.c'))
|
||||
|
64
block/nbd.c
64
block/nbd.c
@ -110,6 +110,10 @@ static void nbd_clear_bdrvstate(BlockDriverState *bs)
|
||||
|
||||
yank_unregister_instance(BLOCKDEV_YANK_INSTANCE(bs->node_name));
|
||||
|
||||
/* Must not leave timers behind that would access freed data */
|
||||
assert(!s->reconnect_delay_timer);
|
||||
assert(!s->open_timer);
|
||||
|
||||
object_unref(OBJECT(s->tlscreds));
|
||||
qapi_free_SocketAddress(s->saddr);
|
||||
s->saddr = NULL;
|
||||
@ -381,6 +385,13 @@ static coroutine_fn void nbd_reconnect_attempt(BDRVNBDState *s)
|
||||
}
|
||||
|
||||
nbd_co_do_establish_connection(s->bs, NULL);
|
||||
|
||||
/*
|
||||
* The reconnect attempt is done (maybe successfully, maybe not), so
|
||||
* we no longer need this timer. Delete it so it will not outlive
|
||||
* this I/O request (so draining removes all timers).
|
||||
*/
|
||||
reconnect_delay_timer_del(s);
|
||||
}
|
||||
|
||||
static coroutine_fn int nbd_receive_replies(BDRVNBDState *s, uint64_t handle)
|
||||
@ -1878,11 +1889,19 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
* The connect attempt is done, so we no longer need this timer.
|
||||
* Delete it, because we do not want it to be around when this node
|
||||
* is drained or closed.
|
||||
*/
|
||||
open_timer_del(s);
|
||||
|
||||
nbd_client_connection_enable_retry(s->conn);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
open_timer_del(s);
|
||||
nbd_clear_bdrvstate(bs);
|
||||
return ret;
|
||||
}
|
||||
@ -2036,6 +2055,42 @@ static void nbd_cancel_in_flight(BlockDriverState *bs)
|
||||
nbd_co_establish_connection_cancel(s->conn);
|
||||
}
|
||||
|
||||
static void nbd_attach_aio_context(BlockDriverState *bs,
|
||||
AioContext *new_context)
|
||||
{
|
||||
BDRVNBDState *s = bs->opaque;
|
||||
|
||||
/* The open_timer is used only during nbd_open() */
|
||||
assert(!s->open_timer);
|
||||
|
||||
/*
|
||||
* The reconnect_delay_timer is scheduled in I/O paths when the
|
||||
* connection is lost, to cancel the reconnection attempt after a
|
||||
* given time. Once this attempt is done (successfully or not),
|
||||
* nbd_reconnect_attempt() ensures the timer is deleted before the
|
||||
* respective I/O request is resumed.
|
||||
* Since the AioContext can only be changed when a node is drained,
|
||||
* the reconnect_delay_timer cannot be active here.
|
||||
*/
|
||||
assert(!s->reconnect_delay_timer);
|
||||
|
||||
if (s->ioc) {
|
||||
qio_channel_attach_aio_context(s->ioc, new_context);
|
||||
}
|
||||
}
|
||||
|
||||
static void nbd_detach_aio_context(BlockDriverState *bs)
|
||||
{
|
||||
BDRVNBDState *s = bs->opaque;
|
||||
|
||||
assert(!s->open_timer);
|
||||
assert(!s->reconnect_delay_timer);
|
||||
|
||||
if (s->ioc) {
|
||||
qio_channel_detach_aio_context(s->ioc);
|
||||
}
|
||||
}
|
||||
|
||||
static BlockDriver bdrv_nbd = {
|
||||
.format_name = "nbd",
|
||||
.protocol_name = "nbd",
|
||||
@ -2059,6 +2114,9 @@ static BlockDriver bdrv_nbd = {
|
||||
.bdrv_dirname = nbd_dirname,
|
||||
.strong_runtime_opts = nbd_strong_runtime_opts,
|
||||
.bdrv_cancel_in_flight = nbd_cancel_in_flight,
|
||||
|
||||
.bdrv_attach_aio_context = nbd_attach_aio_context,
|
||||
.bdrv_detach_aio_context = nbd_detach_aio_context,
|
||||
};
|
||||
|
||||
static BlockDriver bdrv_nbd_tcp = {
|
||||
@ -2084,6 +2142,9 @@ static BlockDriver bdrv_nbd_tcp = {
|
||||
.bdrv_dirname = nbd_dirname,
|
||||
.strong_runtime_opts = nbd_strong_runtime_opts,
|
||||
.bdrv_cancel_in_flight = nbd_cancel_in_flight,
|
||||
|
||||
.bdrv_attach_aio_context = nbd_attach_aio_context,
|
||||
.bdrv_detach_aio_context = nbd_detach_aio_context,
|
||||
};
|
||||
|
||||
static BlockDriver bdrv_nbd_unix = {
|
||||
@ -2109,6 +2170,9 @@ static BlockDriver bdrv_nbd_unix = {
|
||||
.bdrv_dirname = nbd_dirname,
|
||||
.strong_runtime_opts = nbd_strong_runtime_opts,
|
||||
.bdrv_cancel_in_flight = nbd_cancel_in_flight,
|
||||
|
||||
.bdrv_attach_aio_context = nbd_attach_aio_context,
|
||||
.bdrv_detach_aio_context = nbd_detach_aio_context,
|
||||
};
|
||||
|
||||
static void bdrv_nbd_init(void)
|
||||
|
@ -5279,6 +5279,38 @@ static int qcow2_load_vmstate(BlockDriverState *bs, QEMUIOVector *qiov,
|
||||
return bs->drv->bdrv_co_preadv_part(bs, offset, qiov->size, qiov, 0, 0);
|
||||
}
|
||||
|
||||
static int qcow2_has_compressed_clusters(BlockDriverState *bs)
|
||||
{
|
||||
int64_t offset = 0;
|
||||
int64_t bytes = bdrv_getlength(bs);
|
||||
|
||||
if (bytes < 0) {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
while (bytes != 0) {
|
||||
int ret;
|
||||
QCow2SubclusterType type;
|
||||
unsigned int cur_bytes = MIN(INT_MAX, bytes);
|
||||
uint64_t host_offset;
|
||||
|
||||
ret = qcow2_get_host_offset(bs, offset, &cur_bytes, &host_offset,
|
||||
&type);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (type == QCOW2_SUBCLUSTER_COMPRESSED) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
offset += cur_bytes;
|
||||
bytes -= cur_bytes;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Downgrades an image's version. To achieve this, any incompatible features
|
||||
* have to be removed.
|
||||
@ -5336,9 +5368,10 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version,
|
||||
* the first place; if that happens nonetheless, returning -ENOTSUP is the
|
||||
* best thing to do anyway */
|
||||
|
||||
if (s->incompatible_features) {
|
||||
if (s->incompatible_features & ~QCOW2_INCOMPAT_COMPRESSION) {
|
||||
error_setg(errp, "Cannot downgrade an image with incompatible features "
|
||||
"%#" PRIx64 " set", s->incompatible_features);
|
||||
"0x%" PRIx64 " set",
|
||||
s->incompatible_features & ~QCOW2_INCOMPAT_COMPRESSION);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
@ -5356,6 +5389,27 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (s->incompatible_features & QCOW2_INCOMPAT_COMPRESSION) {
|
||||
ret = qcow2_has_compressed_clusters(bs);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Failed to check block status");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (ret) {
|
||||
error_setg(errp, "Cannot downgrade an image with zstd compression "
|
||||
"type and existing compressed clusters");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
/*
|
||||
* No compressed clusters for now, so just chose default zlib
|
||||
* compression.
|
||||
*/
|
||||
s->incompatible_features &= ~QCOW2_INCOMPAT_COMPRESSION;
|
||||
s->compression_type = QCOW2_COMPRESSION_TYPE_ZLIB;
|
||||
}
|
||||
|
||||
assert(s->incompatible_features == 0);
|
||||
|
||||
s->qcow_version = target_version;
|
||||
ret = qcow2_update_header(bs);
|
||||
if (ret < 0) {
|
||||
|
52
block/rbd.c
52
block/rbd.c
@ -1279,11 +1279,11 @@ static int qemu_rbd_diff_iterate_cb(uint64_t offs, size_t len,
|
||||
RBDDiffIterateReq *req = opaque;
|
||||
|
||||
assert(req->offs + req->bytes <= offs);
|
||||
/*
|
||||
* we do not diff against a snapshot so we should never receive a callback
|
||||
* for a hole.
|
||||
*/
|
||||
assert(exists);
|
||||
|
||||
/* treat a hole like an unallocated area and bail out */
|
||||
if (!exists) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!req->exists && offs > req->offs) {
|
||||
/*
|
||||
@ -1320,6 +1320,7 @@ static int coroutine_fn qemu_rbd_co_block_status(BlockDriverState *bs,
|
||||
int status, r;
|
||||
RBDDiffIterateReq req = { .offs = offset };
|
||||
uint64_t features, flags;
|
||||
uint64_t head = 0;
|
||||
|
||||
assert(offset + bytes <= s->image_size);
|
||||
|
||||
@ -1347,7 +1348,43 @@ static int coroutine_fn qemu_rbd_co_block_status(BlockDriverState *bs,
|
||||
return status;
|
||||
}
|
||||
|
||||
r = rbd_diff_iterate2(s->image, NULL, offset, bytes, true, true,
|
||||
#if LIBRBD_VERSION_CODE < LIBRBD_VERSION(1, 17, 0)
|
||||
/*
|
||||
* librbd had a bug until early 2022 that affected all versions of ceph that
|
||||
* supported fast-diff. This bug results in reporting of incorrect offsets
|
||||
* if the offset parameter to rbd_diff_iterate2 is not object aligned.
|
||||
* Work around this bug by rounding down the offset to object boundaries.
|
||||
* This is OK because we call rbd_diff_iterate2 with whole_object = true.
|
||||
* However, this workaround only works for non cloned images with default
|
||||
* striping.
|
||||
*
|
||||
* See: https://tracker.ceph.com/issues/53784
|
||||
*/
|
||||
|
||||
/* check if RBD image has non-default striping enabled */
|
||||
if (features & RBD_FEATURE_STRIPINGV2) {
|
||||
return status;
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
/*
|
||||
* check if RBD image is a clone (= has a parent).
|
||||
*
|
||||
* rbd_get_parent_info is deprecated from Nautilus onwards, but the
|
||||
* replacement rbd_get_parent is not present in Luminous and Mimic.
|
||||
*/
|
||||
if (rbd_get_parent_info(s->image, NULL, 0, NULL, 0, NULL, 0) != -ENOENT) {
|
||||
return status;
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
head = req.offs & (s->object_size - 1);
|
||||
req.offs -= head;
|
||||
bytes += head;
|
||||
#endif
|
||||
|
||||
r = rbd_diff_iterate2(s->image, NULL, req.offs, bytes, true, true,
|
||||
qemu_rbd_diff_iterate_cb, &req);
|
||||
if (r < 0 && r != QEMU_RBD_EXIT_DIFF_ITERATE2) {
|
||||
return status;
|
||||
@ -1366,7 +1403,8 @@ static int coroutine_fn qemu_rbd_co_block_status(BlockDriverState *bs,
|
||||
status = BDRV_BLOCK_ZERO | BDRV_BLOCK_OFFSET_VALID;
|
||||
}
|
||||
|
||||
*pnum = req.bytes;
|
||||
assert(req.bytes > head);
|
||||
*pnum = req.bytes - head;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
11
blockdev.c
11
blockdev.c
@ -3530,6 +3530,7 @@ void qmp_blockdev_reopen(BlockdevOptionsList *reopen_list, Error **errp)
|
||||
{
|
||||
BlockReopenQueue *queue = NULL;
|
||||
GSList *drained = NULL;
|
||||
GSList *p;
|
||||
|
||||
/* Add each one of the BDS that we want to reopen to the queue */
|
||||
for (; reopen_list != NULL; reopen_list = reopen_list->next) {
|
||||
@ -3579,7 +3580,15 @@ void qmp_blockdev_reopen(BlockdevOptionsList *reopen_list, Error **errp)
|
||||
|
||||
fail:
|
||||
bdrv_reopen_queue_free(queue);
|
||||
g_slist_free_full(drained, (GDestroyNotify) bdrv_subtree_drained_end);
|
||||
for (p = drained; p; p = p->next) {
|
||||
BlockDriverState *bs = p->data;
|
||||
AioContext *ctx = bdrv_get_aio_context(bs);
|
||||
|
||||
aio_context_acquire(ctx);
|
||||
bdrv_subtree_drained_end(bs);
|
||||
aio_context_release(ctx);
|
||||
}
|
||||
g_slist_free(drained);
|
||||
}
|
||||
|
||||
void qmp_blockdev_del(const char *node_name, Error **errp)
|
||||
|
@ -59,19 +59,31 @@ abi_long set_sigtramp_args(CPUARMState *env, int sig,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static abi_long get_vfpcontext(CPUARMState *env, abi_ulong frame_addr,
|
||||
struct target_sigframe *frame)
|
||||
{
|
||||
/* see sendsig and get_vfpcontext in sys/arm/arm/exec_machdep.c */
|
||||
target_mcontext_vfp_t *vfp = &frame->sf_vfp;
|
||||
target_mcontext_t *mcp = &frame->sf_uc.uc_mcontext;
|
||||
|
||||
/* Assumes that mcp and vfp are locked */
|
||||
for (int i = 0; i < 32; i++) {
|
||||
vfp->mcv_reg[i] = tswap64(*aa32_vfp_dreg(env, i));
|
||||
}
|
||||
vfp->mcv_fpscr = tswap32(vfp_get_fpscr(env));
|
||||
mcp->mc_vfp_size = tswap32(sizeof(*vfp));
|
||||
mcp->mc_vfp_ptr = tswap32(frame_addr + ((uintptr_t)vfp - (uintptr_t)frame));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare to arm/arm/machdep.c get_mcontext()
|
||||
* Compare to arm/arm/exec_machdep.c get_mcontext()
|
||||
* Assumes that the memory is locked if mcp points to user memory.
|
||||
*/
|
||||
abi_long get_mcontext(CPUARMState *env, target_mcontext_t *mcp, int flags)
|
||||
{
|
||||
int err = 0;
|
||||
uint32_t *gr = mcp->__gregs;
|
||||
|
||||
if (mcp->mc_vfp_size != 0 && mcp->mc_vfp_size != sizeof(target_mcontext_vfp_t)) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
|
||||
gr[TARGET_REG_CPSR] = tswap32(cpsr_read(env));
|
||||
if (flags & TARGET_MC_GET_CLEAR_RET) {
|
||||
gr[TARGET_REG_R0] = 0;
|
||||
@ -97,17 +109,30 @@ abi_long get_mcontext(CPUARMState *env, target_mcontext_t *mcp, int flags)
|
||||
gr[TARGET_REG_LR] = tswap32(env->regs[14]);
|
||||
gr[TARGET_REG_PC] = tswap32(env->regs[15]);
|
||||
|
||||
if (mcp->mc_vfp_size != 0 && mcp->mc_vfp_ptr != 0) {
|
||||
/* see get_vfpcontext in sys/arm/arm/exec_machdep.c */
|
||||
target_mcontext_vfp_t *vfp;
|
||||
vfp = lock_user(VERIFY_WRITE, mcp->mc_vfp_ptr, sizeof(*vfp), 0);
|
||||
for (int i = 0; i < 32; i++) {
|
||||
vfp->mcv_reg[i] = tswap64(*aa32_vfp_dreg(env, i));
|
||||
}
|
||||
vfp->mcv_fpscr = tswap32(vfp_get_fpscr(env));
|
||||
unlock_user(vfp, mcp->mc_vfp_ptr, sizeof(*vfp));
|
||||
}
|
||||
return err;
|
||||
/*
|
||||
* FreeBSD's get_mcontext doesn't save VFP info, but sets the pointer and
|
||||
* size to zero. Applications that need the VFP state use
|
||||
* sysarch(ARM_GET_VFPSTATE) and are expected to adjust mcontext after that.
|
||||
*/
|
||||
mcp->mc_vfp_size = 0;
|
||||
mcp->mc_vfp_ptr = 0;
|
||||
memset(&mcp->mc_spare, 0, sizeof(mcp->mc_spare));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare to arm/arm/exec_machdep.c sendsig()
|
||||
* Assumes that the memory is locked if frame points to user memory.
|
||||
*/
|
||||
abi_long setup_sigframe_arch(CPUARMState *env, abi_ulong frame_addr,
|
||||
struct target_sigframe *frame, int flags)
|
||||
{
|
||||
target_mcontext_t *mcp = &frame->sf_uc.uc_mcontext;
|
||||
|
||||
get_mcontext(env, mcp, flags);
|
||||
get_vfpcontext(env, frame_addr, frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compare to arm/arm/exec_machdep.c set_mcontext() */
|
||||
|
@ -21,6 +21,7 @@
|
||||
#define _TARGET_ARCH_CPU_H_
|
||||
|
||||
#include "target_arch.h"
|
||||
#include "signal-common.h"
|
||||
|
||||
#define TARGET_DEFAULT_CPU_MODEL "any"
|
||||
|
||||
@ -38,8 +39,7 @@ static inline void target_cpu_init(CPUARMState *env,
|
||||
|
||||
static inline void target_cpu_loop(CPUARMState *env)
|
||||
{
|
||||
int trapnr;
|
||||
target_siginfo_t info;
|
||||
int trapnr, si_signo, si_code;
|
||||
unsigned int n;
|
||||
CPUState *cs = env_cpu(env);
|
||||
|
||||
@ -50,33 +50,22 @@ static inline void target_cpu_loop(CPUARMState *env)
|
||||
process_queued_cpu_work(cs);
|
||||
switch (trapnr) {
|
||||
case EXCP_UDEF:
|
||||
{
|
||||
/* See arm/arm/undefined.c undefinedinstruction(); */
|
||||
info.si_addr = env->regs[15];
|
||||
|
||||
/* illegal instruction */
|
||||
info.si_signo = TARGET_SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_ILL_ILLOPC;
|
||||
queue_signal(env, info.si_signo, &info);
|
||||
|
||||
/* TODO: What about instruction emulation? */
|
||||
}
|
||||
case EXCP_NOCP:
|
||||
case EXCP_INVSTATE:
|
||||
/*
|
||||
* See arm/arm/undefined.c undefinedinstruction();
|
||||
*
|
||||
* A number of details aren't emulated (they likely don't matter):
|
||||
* o Misaligned PC generates ILL_ILLADR (these can't come from qemu)
|
||||
* o Thumb-2 instructions generate ILLADR
|
||||
* o Both modes implement coprocessor instructions, which we don't
|
||||
* do here. FreeBSD just implements them for the VFP coprocessor
|
||||
* and special kernel breakpoints, trace points, dtrace, etc.
|
||||
*/
|
||||
force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->regs[15]);
|
||||
break;
|
||||
case EXCP_SWI:
|
||||
case EXCP_BKPT:
|
||||
{
|
||||
/*
|
||||
* system call
|
||||
* See arm/arm/trap.c cpu_fetch_syscall_args()
|
||||
*/
|
||||
if (trapnr == EXCP_BKPT) {
|
||||
if (env->thumb) {
|
||||
env->regs[15] += 2;
|
||||
} else {
|
||||
env->regs[15] += 4;
|
||||
}
|
||||
}
|
||||
n = env->regs[7];
|
||||
if (bsd_type == target_freebsd) {
|
||||
int ret;
|
||||
@ -84,7 +73,7 @@ static inline void target_cpu_loop(CPUARMState *env)
|
||||
int32_t syscall_nr = n;
|
||||
int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
|
||||
|
||||
/* See arm/arm/trap.c cpu_fetch_syscall_args() */
|
||||
/* See arm/arm/syscall.c cpu_fetch_syscall_args() */
|
||||
if (syscall_nr == TARGET_FREEBSD_NR_syscall) {
|
||||
syscall_nr = env->regs[0];
|
||||
arg1 = env->regs[1];
|
||||
@ -160,32 +149,52 @@ static inline void target_cpu_loop(CPUARMState *env)
|
||||
/* just indicate that signals should be handled asap */
|
||||
break;
|
||||
case EXCP_PREFETCH_ABORT:
|
||||
/* See arm/arm/trap.c prefetch_abort_handler() */
|
||||
case EXCP_DATA_ABORT:
|
||||
/* See arm/arm/trap.c data_abort_handler() */
|
||||
info.si_signo = TARGET_SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
/* XXX: check env->error_code */
|
||||
info.si_code = 0;
|
||||
info.si_addr = env->exception.vaddress;
|
||||
queue_signal(env, info.si_signo, &info);
|
||||
/*
|
||||
* See arm/arm/trap-v6.c prefetch_abort_handler() and
|
||||
* data_abort_handler()
|
||||
*
|
||||
* However, FreeBSD maps these to a generic value and then uses that
|
||||
* to maybe fault in pages in vm/vm_fault.c:vm_fault_trap(). I
|
||||
* believe that the indirection maps the same as Linux, but haven't
|
||||
* chased down every single possible indirection.
|
||||
*/
|
||||
|
||||
/* For user-only we don't set TTBCR_EAE, so look at the FSR. */
|
||||
switch (env->exception.fsr & 0x1f) {
|
||||
case 0x1: /* Alignment */
|
||||
si_signo = TARGET_SIGBUS;
|
||||
si_code = TARGET_BUS_ADRALN;
|
||||
break;
|
||||
case 0x3: /* Access flag fault, level 1 */
|
||||
case 0x6: /* Access flag fault, level 2 */
|
||||
case 0x9: /* Domain fault, level 1 */
|
||||
case 0xb: /* Domain fault, level 2 */
|
||||
case 0xd: /* Permission fault, level 1 */
|
||||
case 0xf: /* Permission fault, level 2 */
|
||||
si_signo = TARGET_SIGSEGV;
|
||||
si_code = TARGET_SEGV_ACCERR;
|
||||
break;
|
||||
case 0x5: /* Translation fault, level 1 */
|
||||
case 0x7: /* Translation fault, level 2 */
|
||||
si_signo = TARGET_SIGSEGV;
|
||||
si_code = TARGET_SEGV_MAPERR;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
force_sig_fault(si_signo, si_code, env->exception.vaddress);
|
||||
break;
|
||||
case EXCP_DEBUG:
|
||||
{
|
||||
|
||||
info.si_signo = TARGET_SIGTRAP;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_TRAP_BRKPT;
|
||||
info.si_addr = env->exception.vaddress;
|
||||
queue_signal(env, info.si_signo, &info);
|
||||
}
|
||||
break;
|
||||
case EXCP_ATOMIC:
|
||||
cpu_exec_step_atomic(cs);
|
||||
case EXCP_BKPT:
|
||||
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->regs[15]);
|
||||
break;
|
||||
case EXCP_YIELD:
|
||||
/* nothing to do here for user-mode, just resume guest code */
|
||||
break;
|
||||
case EXCP_ATOMIC:
|
||||
cpu_exec_step_atomic(cs);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
|
||||
trapnr);
|
||||
@ -204,7 +213,7 @@ static inline void target_cpu_clone_regs(CPUARMState *env, target_ulong newsp)
|
||||
env->regs[0] = 0;
|
||||
}
|
||||
|
||||
static inline void target_cpu_reset(CPUArchState *cpu)
|
||||
static inline void target_cpu_reset(CPUArchState *env)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -71,11 +71,24 @@ typedef struct target_siginfo {
|
||||
int32_t _mqd;
|
||||
} _mesgp;
|
||||
|
||||
/* SIGPOLL */
|
||||
/* SIGPOLL -- Not really genreated in FreeBSD ??? */
|
||||
struct {
|
||||
int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
|
||||
} _poll;
|
||||
|
||||
struct {
|
||||
int _mqd;
|
||||
} _mesgq;
|
||||
|
||||
struct {
|
||||
/*
|
||||
* Syscall number for signals delivered as a result of system calls
|
||||
* denied by Capsicum.
|
||||
*/
|
||||
int _syscall;
|
||||
} _capsicum;
|
||||
|
||||
/* Spare for future growth */
|
||||
struct {
|
||||
abi_long __spare1__;
|
||||
int32_t __spare2_[7];
|
||||
|
@ -4,6 +4,9 @@
|
||||
#include "target_os_siginfo.h"
|
||||
#include "target_arch_signal.h"
|
||||
|
||||
abi_long setup_sigframe_arch(CPUArchState *env, abi_ulong frame_addr,
|
||||
struct target_sigframe *frame, int flags);
|
||||
|
||||
/* Compare to sys/signal.h */
|
||||
#define TARGET_SIGHUP 1 /* hangup */
|
||||
#define TARGET_SIGINT 2 /* interrupt */
|
||||
|
@ -36,9 +36,9 @@ abi_long set_sigtramp_args(CPUArchState *env, int sig,
|
||||
struct target_sigframe *frame,
|
||||
abi_ulong frame_addr,
|
||||
struct target_sigaction *ka);
|
||||
abi_long get_mcontext(CPUArchState *regs, target_mcontext_t *mcp, int flags);
|
||||
abi_long set_mcontext(CPUArchState *regs, target_mcontext_t *mcp, int srflag);
|
||||
abi_long get_ucontext_sigreturn(CPUArchState *regs, abi_ulong target_sf,
|
||||
abi_long get_mcontext(CPUArchState *env, target_mcontext_t *mcp, int flags);
|
||||
abi_long set_mcontext(CPUArchState *env, target_mcontext_t *mcp, int srflag);
|
||||
abi_long get_ucontext_sigreturn(CPUArchState *env, abi_ulong target_sf,
|
||||
abi_ulong *target_uc);
|
||||
|
||||
#endif /* TARGET_OS_UCONTEXT_H */
|
||||
|
35
bsd-user/host/arm/host-signal.h
Normal file
35
bsd-user/host/arm/host-signal.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* host-signal.h: signal info dependent on the host architecture
|
||||
*
|
||||
* Copyright (c) 2021 Warner Losh
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef ARM_HOST_SIGNAL_H
|
||||
#define ARM_HOST_SIGNAL_H
|
||||
|
||||
#include <sys/ucontext.h>
|
||||
|
||||
static inline uintptr_t host_signal_pc(ucontext_t *uc)
|
||||
{
|
||||
return uc->uc_mcontext.__gregs[_REG_PC];
|
||||
}
|
||||
|
||||
static inline void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
|
||||
{
|
||||
uc->uc_mcontext.__gregs[_REG_PC] = pc;
|
||||
}
|
||||
|
||||
static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
|
||||
{
|
||||
/*
|
||||
* In the FSR, bit 11 is WnR. FreeBSD returns this as part of the
|
||||
* si_info.si_trapno.
|
||||
*/
|
||||
uint32_t fsr = info->si_trapno;
|
||||
|
||||
return extract32(fsr, 11, 1);
|
||||
}
|
||||
|
||||
#endif
|
37
bsd-user/host/i386/host-signal.h
Normal file
37
bsd-user/host/i386/host-signal.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* host-signal.h: signal info dependent on the host architecture
|
||||
*
|
||||
* Copyright (c) 2021 Warner Losh
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef I386_HOST_SIGNAL_H
|
||||
#define I386_HOST_SIGNAL_H
|
||||
|
||||
#include <sys/ucontext.h>
|
||||
#include <machine/trap.h>
|
||||
#include <vm/pmap.h>
|
||||
#include <machine/pmap.h>
|
||||
|
||||
static inline uintptr_t host_signal_pc(ucontext_t *uc)
|
||||
{
|
||||
return uc->uc_mcontext.mc_eip;
|
||||
}
|
||||
|
||||
static inline void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
|
||||
{
|
||||
uc->uc_mcontext.mc_eip = pc;
|
||||
}
|
||||
|
||||
static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
|
||||
{
|
||||
/*
|
||||
* Look in sys/i386/i386/trap.c. NOTE: mc_err == tr_err due to type punning
|
||||
* between a trapframe and mcontext on FreeBSD/i386.
|
||||
*/
|
||||
return uc->uc_mcontext.mc_trapno == T_PAGEFLT &&
|
||||
uc->uc_mcontext.mc_err & PGEX_W;
|
||||
}
|
||||
|
||||
#endif
|
37
bsd-user/host/x86_64/host-signal.h
Normal file
37
bsd-user/host/x86_64/host-signal.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* host-signal.h: signal info dependent on the host architecture
|
||||
*
|
||||
* Copyright (c) 2021 Warner Losh
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef X86_64_HOST_SIGNAL_H
|
||||
#define X86_64_HOST_SIGNAL_H
|
||||
|
||||
#include <sys/ucontext.h>
|
||||
#include <machine/trap.h>
|
||||
#include <vm/pmap.h>
|
||||
#include <machine/pmap.h>
|
||||
|
||||
static inline uintptr_t host_signal_pc(ucontext_t *uc)
|
||||
{
|
||||
return uc->uc_mcontext.mc_rip;
|
||||
}
|
||||
|
||||
static inline void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
|
||||
{
|
||||
uc->uc_mcontext.mc_rip = pc;
|
||||
}
|
||||
|
||||
static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
|
||||
{
|
||||
/*
|
||||
* Look in sys/amd64/amd64/trap.c. NOTE: mc_err == tr_err due to type
|
||||
* punning between a trapframe and mcontext on FreeBSD/amd64.
|
||||
*/
|
||||
return uc->uc_mcontext.mc_trapno == T_PAGEFLT &&
|
||||
uc->uc_mcontext.mc_err & PGEX_W;
|
||||
}
|
||||
|
||||
#endif
|
@ -32,6 +32,19 @@ abi_long set_sigtramp_args(CPUX86State *env, int sig,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare to i386/i386/exec_machdep.c sendsig()
|
||||
* Assumes that the memory is locked if frame points to user memory.
|
||||
*/
|
||||
abi_long setup_sigframe_arch(CPUX86State *env, abi_ulong frame_addr,
|
||||
struct target_sigframe *frame, int flags)
|
||||
{
|
||||
target_mcontext_t *mcp = &frame->sf_uc.uc_mcontext;
|
||||
|
||||
get_mcontext(env, mcp, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compare to i386/i386/machdep.c get_mcontext() */
|
||||
abi_long get_mcontext(CPUX86State *regs, target_mcontext_t *mcp, int flags)
|
||||
{
|
||||
|
@ -20,6 +20,7 @@
|
||||
#define _TARGET_ARCH_CPU_H_
|
||||
|
||||
#include "target_arch.h"
|
||||
#include "signal-common.h"
|
||||
|
||||
#define TARGET_DEFAULT_CPU_MODEL "qemu32"
|
||||
|
||||
@ -199,9 +200,9 @@ static inline void target_cpu_clone_regs(CPUX86State *env, target_ulong newsp)
|
||||
env->regs[R_EAX] = 0;
|
||||
}
|
||||
|
||||
static inline void target_cpu_reset(CPUArchState *cpu)
|
||||
static inline void target_cpu_reset(CPUArchState *env)
|
||||
{
|
||||
cpu_reset(env_cpu(cpu));
|
||||
cpu_reset(env_cpu(env));
|
||||
}
|
||||
|
||||
#endif /* ! _TARGET_ARCH_CPU_H_ */
|
||||
|
@ -215,15 +215,13 @@ void qemu_cpu_kick(CPUState *cpu)
|
||||
}
|
||||
|
||||
/* Assumes contents are already zeroed. */
|
||||
void init_task_state(TaskState *ts)
|
||||
static void init_task_state(TaskState *ts)
|
||||
{
|
||||
int i;
|
||||
|
||||
ts->first_free = ts->sigqueue_table;
|
||||
for (i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) {
|
||||
ts->sigqueue_table[i].next = &ts->sigqueue_table[i + 1];
|
||||
}
|
||||
ts->sigqueue_table[i].next = NULL;
|
||||
ts->sigaltstack_used = (struct target_sigaltstack) {
|
||||
.ss_sp = 0,
|
||||
.ss_size = 0,
|
||||
.ss_flags = TARGET_SS_DISABLE,
|
||||
};
|
||||
}
|
||||
|
||||
void gemu_log(const char *fmt, ...)
|
||||
|
@ -70,17 +70,9 @@ struct image_info {
|
||||
uint32_t elf_flags;
|
||||
};
|
||||
|
||||
#define MAX_SIGQUEUE_SIZE 1024
|
||||
|
||||
struct qemu_sigqueue {
|
||||
struct qemu_sigqueue *next;
|
||||
target_siginfo_t info;
|
||||
};
|
||||
|
||||
struct emulated_sigtable {
|
||||
int pending; /* true if signal is pending */
|
||||
struct qemu_sigqueue *first;
|
||||
struct qemu_sigqueue info; /* Put first signal info here */
|
||||
target_siginfo_t info;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -93,15 +85,39 @@ typedef struct TaskState {
|
||||
struct bsd_binprm *bprm;
|
||||
struct image_info *info;
|
||||
|
||||
struct emulated_sigtable sync_signal;
|
||||
/*
|
||||
* TODO: Since we block all signals while returning to the main CPU
|
||||
* loop, this needn't be an array
|
||||
*/
|
||||
struct emulated_sigtable sigtab[TARGET_NSIG];
|
||||
struct qemu_sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
|
||||
struct qemu_sigqueue *first_free; /* first free siginfo queue entry */
|
||||
int signal_pending; /* non zero if a signal may be pending */
|
||||
/*
|
||||
* Nonzero if process_pending_signals() needs to do something (either
|
||||
* handle a pending signal or unblock signals).
|
||||
* This flag is written from a signal handler so should be accessed via
|
||||
* the qatomic_read() and qatomic_set() functions. (It is not accessed
|
||||
* from multiple threads.)
|
||||
*/
|
||||
int signal_pending;
|
||||
/* True if we're leaving a sigsuspend and sigsuspend_mask is valid. */
|
||||
bool in_sigsuspend;
|
||||
/*
|
||||
* This thread's signal mask, as requested by the guest program.
|
||||
* The actual signal mask of this thread may differ:
|
||||
* + we don't let SIGSEGV and SIGBUS be blocked while running guest code
|
||||
* + sometimes we block all signals to avoid races
|
||||
*/
|
||||
sigset_t signal_mask;
|
||||
/*
|
||||
* The signal mask imposed by a guest sigsuspend syscall, if we are
|
||||
* currently in the middle of such a syscall
|
||||
*/
|
||||
sigset_t sigsuspend_mask;
|
||||
|
||||
uint8_t stack[];
|
||||
/* This thread's sigaltstack, if it has one */
|
||||
struct target_sigaltstack sigaltstack_used;
|
||||
} __attribute__((aligned(16))) TaskState;
|
||||
|
||||
void init_task_state(TaskState *ts);
|
||||
void stop_all_tasks(void);
|
||||
extern const char *qemu_uname_release;
|
||||
|
||||
@ -201,16 +217,18 @@ print_openbsd_syscall(int num,
|
||||
abi_long arg1, abi_long arg2, abi_long arg3,
|
||||
abi_long arg4, abi_long arg5, abi_long arg6);
|
||||
void print_openbsd_syscall_ret(int num, abi_long ret);
|
||||
/**
|
||||
* print_taken_signal:
|
||||
* @target_signum: target signal being taken
|
||||
* @tinfo: target_siginfo_t which will be passed to the guest for the signal
|
||||
*
|
||||
* Print strace output indicating that this signal is being taken by the guest,
|
||||
* in a format similar to:
|
||||
* --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} ---
|
||||
*/
|
||||
void print_taken_signal(int target_signum, const target_siginfo_t *tinfo);
|
||||
extern int do_strace;
|
||||
|
||||
/* signal.c */
|
||||
void process_pending_signals(CPUArchState *cpu_env);
|
||||
void signal_init(void);
|
||||
long do_sigreturn(CPUArchState *env);
|
||||
long do_rt_sigreturn(CPUArchState *env);
|
||||
void queue_signal(CPUArchState *env, int sig, target_siginfo_t *info);
|
||||
abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp);
|
||||
|
||||
/* mmap.c */
|
||||
int target_mprotect(abi_ulong start, abi_ulong len, int prot);
|
||||
abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
|
||||
@ -451,4 +469,6 @@ static inline void *lock_user_string(abi_ulong guest_addr)
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "user/safe-syscall.h"
|
||||
|
||||
#endif /* QEMU_H */
|
||||
|
75
bsd-user/signal-common.h
Normal file
75
bsd-user/signal-common.h
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Emulation of BSD signals
|
||||
*
|
||||
* Copyright (c) 2013 Stacey Son
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef SIGNAL_COMMON_H
|
||||
#define SIGNAL_COMMON_H
|
||||
|
||||
/**
|
||||
* block_signals: block all signals while handling this guest syscall
|
||||
*
|
||||
* Block all signals, and arrange that the signal mask is returned to
|
||||
* its correct value for the guest before we resume execution of guest code.
|
||||
* If this function returns non-zero, then the caller should immediately
|
||||
* return -TARGET_ERESTARTSYS to the main loop, which will take the pending
|
||||
* signal and restart execution of the syscall.
|
||||
* If block_signals() returns zero, then the caller can continue with
|
||||
* emulation of the system call knowing that no signals can be taken
|
||||
* (and therefore that no race conditions will result).
|
||||
* This should only be called once, because if it is called a second time
|
||||
* it will always return non-zero. (Think of it like a mutex that can't
|
||||
* be recursively locked.)
|
||||
* Signals will be unblocked again by process_pending_signals().
|
||||
*
|
||||
* Return value: non-zero if there was a pending signal, zero if not.
|
||||
*/
|
||||
int block_signals(void); /* Returns non zero if signal pending */
|
||||
|
||||
long do_rt_sigreturn(CPUArchState *env);
|
||||
int do_sigaction(int sig, const struct target_sigaction *act,
|
||||
struct target_sigaction *oact);
|
||||
abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp);
|
||||
long do_sigreturn(CPUArchState *env, abi_ulong addr);
|
||||
void force_sig_fault(int sig, int code, abi_ulong addr);
|
||||
int host_to_target_signal(int sig);
|
||||
void host_to_target_sigset(target_sigset_t *d, const sigset_t *s);
|
||||
void process_pending_signals(CPUArchState *env);
|
||||
void queue_signal(CPUArchState *env, int sig, int si_type,
|
||||
target_siginfo_t *info);
|
||||
void signal_init(void);
|
||||
int target_to_host_signal(int sig);
|
||||
void target_to_host_sigset(sigset_t *d, const target_sigset_t *s);
|
||||
|
||||
/*
|
||||
* Within QEMU the top 8 bits of si_code indicate which of the parts of the
|
||||
* union in target_siginfo is valid. This only applies between
|
||||
* host_to_target_siginfo_noswap() and tswap_siginfo(); it does not appear
|
||||
* either within host siginfo_t or in target_siginfo structures which we get
|
||||
* from the guest userspace program. Linux kenrels use this internally, but BSD
|
||||
* kernels don't do this, but its a useful abstraction.
|
||||
*
|
||||
* The linux-user version of this uses the top 16 bits, but FreeBSD's SI_USER
|
||||
* and other signal indepenent SI_ codes have bit 16 set, so we only use the top
|
||||
* byte instead.
|
||||
*
|
||||
* For FreeBSD, we have si_pid, si_uid, si_status, and si_addr always. Linux and
|
||||
* {Open,Net}BSD have a different approach (where their reason field is larger,
|
||||
* but whose siginfo has fewer fields always).
|
||||
*
|
||||
* QEMU_SI_CAPSICUM is currently only FreeBSD 14 current only, so only define
|
||||
* it where _capsicum is available.
|
||||
*/
|
||||
#define QEMU_SI_NOINFO 0 /* nothing other than si_signo valid */
|
||||
#define QEMU_SI_FAULT 1 /* _fault is valid in _reason */
|
||||
#define QEMU_SI_TIMER 2 /* _timer is valid in _reason */
|
||||
#define QEMU_SI_MESGQ 3 /* _mesgq is valid in _reason */
|
||||
#define QEMU_SI_POLL 4 /* _poll is valid in _reason */
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version >= 1400026
|
||||
#define QEMU_SI_CAPSICUM 5 /* _capsicum is valid in _reason */
|
||||
#endif
|
||||
|
||||
#endif
|
1013
bsd-user/signal.c
1013
bsd-user/signal.c
File diff suppressed because it is too large
Load Diff
@ -31,6 +31,24 @@ int do_strace;
|
||||
/*
|
||||
* Utility functions
|
||||
*/
|
||||
static const char *
|
||||
get_comma(int last)
|
||||
{
|
||||
return (last) ? "" : ",";
|
||||
}
|
||||
|
||||
/*
|
||||
* Prints out raw parameter using given format. Caller needs
|
||||
* to do byte swapping if needed.
|
||||
*/
|
||||
static void
|
||||
print_raw_param(const char *fmt, abi_long param, int last)
|
||||
{
|
||||
char format[64];
|
||||
|
||||
(void)snprintf(format, sizeof(format), "%s%s", fmt, get_comma(last));
|
||||
gemu_log(format, param);
|
||||
}
|
||||
|
||||
static void print_sysctl(const struct syscallname *name, abi_long arg1,
|
||||
abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5,
|
||||
@ -239,3 +257,82 @@ void print_openbsd_syscall_ret(int num, abi_long ret)
|
||||
|
||||
print_syscall_ret(num, ret, openbsd_scnames, ARRAY_SIZE(openbsd_scnames));
|
||||
}
|
||||
|
||||
static void
|
||||
print_signal(abi_ulong arg, int last)
|
||||
{
|
||||
const char *signal_name = NULL;
|
||||
switch (arg) {
|
||||
case TARGET_SIGHUP:
|
||||
signal_name = "SIGHUP";
|
||||
break;
|
||||
case TARGET_SIGINT:
|
||||
signal_name = "SIGINT";
|
||||
break;
|
||||
case TARGET_SIGQUIT:
|
||||
signal_name = "SIGQUIT";
|
||||
break;
|
||||
case TARGET_SIGILL:
|
||||
signal_name = "SIGILL";
|
||||
break;
|
||||
case TARGET_SIGABRT:
|
||||
signal_name = "SIGABRT";
|
||||
break;
|
||||
case TARGET_SIGFPE:
|
||||
signal_name = "SIGFPE";
|
||||
break;
|
||||
case TARGET_SIGKILL:
|
||||
signal_name = "SIGKILL";
|
||||
break;
|
||||
case TARGET_SIGSEGV:
|
||||
signal_name = "SIGSEGV";
|
||||
break;
|
||||
case TARGET_SIGPIPE:
|
||||
signal_name = "SIGPIPE";
|
||||
break;
|
||||
case TARGET_SIGALRM:
|
||||
signal_name = "SIGALRM";
|
||||
break;
|
||||
case TARGET_SIGTERM:
|
||||
signal_name = "SIGTERM";
|
||||
break;
|
||||
case TARGET_SIGUSR1:
|
||||
signal_name = "SIGUSR1";
|
||||
break;
|
||||
case TARGET_SIGUSR2:
|
||||
signal_name = "SIGUSR2";
|
||||
break;
|
||||
case TARGET_SIGCHLD:
|
||||
signal_name = "SIGCHLD";
|
||||
break;
|
||||
case TARGET_SIGCONT:
|
||||
signal_name = "SIGCONT";
|
||||
break;
|
||||
case TARGET_SIGSTOP:
|
||||
signal_name = "SIGSTOP";
|
||||
break;
|
||||
case TARGET_SIGTTIN:
|
||||
signal_name = "SIGTTIN";
|
||||
break;
|
||||
case TARGET_SIGTTOU:
|
||||
signal_name = "SIGTTOU";
|
||||
break;
|
||||
}
|
||||
if (signal_name == NULL) {
|
||||
print_raw_param("%ld", arg, last);
|
||||
return;
|
||||
}
|
||||
gemu_log("%s%s", signal_name, get_comma(last));
|
||||
}
|
||||
|
||||
void print_taken_signal(int target_signum, const target_siginfo_t *tinfo)
|
||||
{
|
||||
/*
|
||||
* Print the strace output for a signal being taken:
|
||||
* --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} ---
|
||||
*/
|
||||
gemu_log("%d ", getpid());
|
||||
gemu_log("--- ");
|
||||
print_signal(target_signum, 1);
|
||||
gemu_log(" ---\n");
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#define _SYSCALL_DEFS_H_
|
||||
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include "errno_defs.h"
|
||||
|
||||
|
11
bsd-user/trace-events
Normal file
11
bsd-user/trace-events
Normal file
@ -0,0 +1,11 @@
|
||||
# See docs/tracing.txt for syntax documentation.
|
||||
|
||||
# bsd-user/signal.c
|
||||
user_setup_frame(void *env, uint64_t frame_addr) "env=%p frame_addr=0x%"PRIx64
|
||||
user_setup_rt_frame(void *env, uint64_t frame_addr) "env=%p frame_addr=0x%"PRIx64
|
||||
user_do_rt_sigreturn(void *env, uint64_t frame_addr) "env=%p frame_addr=0x%"PRIx64
|
||||
user_do_sigreturn(void *env, uint64_t frame_addr) "env=%p frame_addr=0x%"PRIx64
|
||||
user_dump_core_and_abort(void *env, int target_sig, int host_sig) "env=%p signal %d (host %d)"
|
||||
user_handle_signal(void *env, int target_sig) "env=%p signal %d"
|
||||
user_host_signal(void *env, int host_sig, int target_sig) "env=%p signal %d (target %d("
|
||||
user_queue_signal(void *env, int target_sig) "env=%p signal %d"
|
1
bsd-user/trace.h
Normal file
1
bsd-user/trace.h
Normal file
@ -0,0 +1 @@
|
||||
#include "trace/trace-bsd_user.h"
|
@ -30,6 +30,19 @@ abi_long set_sigtramp_args(CPUX86State *regs,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare to amd64/amd64/exec_machdep.c sendsig()
|
||||
* Assumes that the memory is locked if frame points to user memory.
|
||||
*/
|
||||
abi_long setup_sigframe_arch(CPUX86State *env, abi_ulong frame_addr,
|
||||
struct target_sigframe *frame, int flags)
|
||||
{
|
||||
target_mcontext_t *mcp = &frame->sf_uc.uc_mcontext;
|
||||
|
||||
get_mcontext(env, mcp, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compare to amd64/amd64/machdep.c get_mcontext() */
|
||||
abi_long get_mcontext(CPUX86State *regs,
|
||||
target_mcontext_t *mcp, int flags)
|
||||
|
@ -20,6 +20,7 @@
|
||||
#define _TARGET_ARCH_CPU_H_
|
||||
|
||||
#include "target_arch.h"
|
||||
#include "signal-common.h"
|
||||
|
||||
#define TARGET_DEFAULT_CPU_MODEL "qemu64"
|
||||
|
||||
@ -237,9 +238,9 @@ static inline void target_cpu_clone_regs(CPUX86State *env, target_ulong newsp)
|
||||
env->regs[R_EAX] = 0;
|
||||
}
|
||||
|
||||
static inline void target_cpu_reset(CPUArchState *cpu)
|
||||
static inline void target_cpu_reset(CPUArchState *env)
|
||||
{
|
||||
cpu_reset(env_cpu(cpu));
|
||||
cpu_reset(env_cpu(env));
|
||||
}
|
||||
|
||||
#endif /* ! _TARGET_ARCH_CPU_H_ */
|
||||
|
@ -24,7 +24,8 @@
|
||||
.type safe_syscall_end, @function
|
||||
|
||||
#define STACK_BIAS 2047
|
||||
#define PARAM(N) STACK_BIAS + N*8
|
||||
#define WINDOW_SIZE 16 * 8
|
||||
#define PARAM(N) STACK_BIAS + WINDOW_SIZE + N * 8
|
||||
|
||||
/*
|
||||
* This is the entry point for making a system call. The calling
|
||||
@ -74,7 +75,7 @@ safe_syscall_end:
|
||||
/* code path for having successfully executed the syscall */
|
||||
bcs,pn %xcc, 1f
|
||||
nop
|
||||
ret
|
||||
retl
|
||||
nop
|
||||
|
||||
/* code path when we didn't execute the syscall */
|
||||
|
@ -1,8 +0,0 @@
|
||||
TARGET_ARCH=ppc64
|
||||
TARGET_ABI32=y
|
||||
TARGET_BASE_ARCH=ppc
|
||||
TARGET_ABI_DIR=ppc
|
||||
TARGET_SYSTBL_ABI=common,nospu,32
|
||||
TARGET_SYSTBL=syscall.tbl
|
||||
TARGET_WORDS_BIGENDIAN=y
|
||||
TARGET_XML_FILES= gdb-xml/power64-core.xml gdb-xml/power-fpu.xml gdb-xml/power-altivec.xml gdb-xml/power-spe.xml gdb-xml/power-vsx.xml
|
35
configure
vendored
35
configure
vendored
@ -402,7 +402,7 @@ for opt do
|
||||
;;
|
||||
--cross-cc-*[!a-zA-Z0-9_-]*=*) error_exit "Passed bad --cross-cc-FOO option"
|
||||
;;
|
||||
--cross-cc-cflags-*) cc_arch=${opt#--cross-cc-flags-}; cc_arch=${cc_arch%%=*}
|
||||
--cross-cc-cflags-*) cc_arch=${opt#--cross-cc-cflags-}; cc_arch=${cc_arch%%=*}
|
||||
eval "cross_cc_cflags_${cc_arch}=\$optarg"
|
||||
cross_cc_vars="$cross_cc_vars cross_cc_cflags_${cc_arch}"
|
||||
;;
|
||||
@ -1264,8 +1264,6 @@ if eval test -z "\${cross_cc_$cpu}"; then
|
||||
fi
|
||||
|
||||
default_target_list=""
|
||||
deprecated_targets_list=ppc64abi32-linux-user
|
||||
deprecated_features=""
|
||||
mak_wilds=""
|
||||
|
||||
if [ "$linux_user" != no ]; then
|
||||
@ -1293,16 +1291,6 @@ if [ "$bsd_user" = "yes" ]; then
|
||||
mak_wilds="${mak_wilds} $source_path/configs/targets/*-bsd-user.mak"
|
||||
fi
|
||||
|
||||
# If the user doesn't explicitly specify a deprecated target we will
|
||||
# skip it.
|
||||
if test -z "$target_list"; then
|
||||
if test -z "$target_list_exclude"; then
|
||||
target_list_exclude="$deprecated_targets_list"
|
||||
else
|
||||
target_list_exclude="$target_list_exclude,$deprecated_targets_list"
|
||||
fi
|
||||
fi
|
||||
|
||||
for config in $mak_wilds; do
|
||||
target="$(basename "$config" .mak)"
|
||||
if echo "$target_list_exclude" | grep -vq "$target"; then
|
||||
@ -1321,11 +1309,9 @@ Standard options:
|
||||
--prefix=PREFIX install in PREFIX [$prefix]
|
||||
--interp-prefix=PREFIX where to find shared libraries, etc.
|
||||
use %M for cpu name [$interp_prefix]
|
||||
--target-list=LIST set target list (default: build all non-deprecated)
|
||||
--target-list=LIST set target list (default: build all)
|
||||
$(echo Available targets: $default_target_list | \
|
||||
fold -s -w 53 | sed -e 's/^/ /')
|
||||
$(echo Deprecated targets: $deprecated_targets_list | \
|
||||
fold -s -w 53 | sed -e 's/^/ /')
|
||||
--target-list-exclude=LIST exclude a set of targets from the default target-list
|
||||
|
||||
Advanced options (experts only):
|
||||
@ -1340,7 +1326,7 @@ Advanced options (experts only):
|
||||
--extra-cxxflags=CXXFLAGS append extra C++ compiler flags CXXFLAGS
|
||||
--extra-ldflags=LDFLAGS append extra linker flags LDFLAGS
|
||||
--cross-cc-ARCH=CC use compiler when building ARCH guest test cases
|
||||
--cross-cc-flags-ARCH= use compiler flags when building ARCH guest tests
|
||||
--cross-cc-cflags-ARCH= use compiler flags when building ARCH guest tests
|
||||
--make=MAKE use specified make [$make]
|
||||
--python=PYTHON use specified python [$python]
|
||||
--sphinx-build=SPHINX use specified sphinx-build [$sphinx_build]
|
||||
@ -1809,13 +1795,6 @@ else
|
||||
done
|
||||
fi
|
||||
|
||||
for target in $target_list; do
|
||||
# if a deprecated target is enabled we note it here
|
||||
if echo "$deprecated_targets_list" | grep -q "$target"; then
|
||||
add_to deprecated_features $target
|
||||
fi
|
||||
done
|
||||
|
||||
# see if system emulation was really requested
|
||||
case " $target_list " in
|
||||
*"-softmmu "*) softmmu=yes
|
||||
@ -2780,7 +2759,7 @@ cat > $TMPC << EOF
|
||||
#include <cpuid.h>
|
||||
int main(void) {
|
||||
unsigned a, b, c, d;
|
||||
int max = __get_cpuid_max(0, 0);
|
||||
unsigned max = __get_cpuid_max(0, 0);
|
||||
|
||||
if (max >= 1) {
|
||||
__cpuid(1, a, b, c, d);
|
||||
@ -3849,12 +3828,6 @@ else
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "${deprecated_features}"; then
|
||||
echo "Warning, deprecated features enabled."
|
||||
echo "Please see docs/about/deprecated.rst"
|
||||
echo " features: ${deprecated_features}"
|
||||
fi
|
||||
|
||||
# Save the configure command line for later reuse.
|
||||
cat <<EOD >config.status
|
||||
#!/bin/sh
|
||||
|
@ -20,6 +20,7 @@ NAMES += howvec
|
||||
NAMES += lockstep
|
||||
NAMES += hwprofile
|
||||
NAMES += cache
|
||||
NAMES += drcov
|
||||
|
||||
SONAMES := $(addsuffix .so,$(addprefix lib,$(NAMES)))
|
||||
|
||||
|
163
contrib/plugins/drcov.c
Normal file
163
contrib/plugins/drcov.c
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (C) 2021, Ivanov Arkady <arkadiy.ivanov@ispras.ru>
|
||||
*
|
||||
* Drcov - a DynamoRIO-based tool that collects coverage information
|
||||
* from a binary. Primary goal this script is to have coverage log
|
||||
* files that work in Lighthouse.
|
||||
*
|
||||
* License: GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include <qemu-plugin.h>
|
||||
|
||||
QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
|
||||
|
||||
static char header[] = "DRCOV VERSION: 2\n"
|
||||
"DRCOV FLAVOR: drcov-64\n"
|
||||
"Module Table: version 2, count 1\n"
|
||||
"Columns: id, base, end, entry, path\n";
|
||||
|
||||
static FILE *fp;
|
||||
static const char *file_name = "file.drcov.trace";
|
||||
static GMutex lock;
|
||||
|
||||
typedef struct {
|
||||
uint32_t start;
|
||||
uint16_t size;
|
||||
uint16_t mod_id;
|
||||
bool exec;
|
||||
} bb_entry_t;
|
||||
|
||||
/* Translated blocks */
|
||||
static GPtrArray *blocks;
|
||||
|
||||
static void printf_header(unsigned long count)
|
||||
{
|
||||
fprintf(fp, "%s", header);
|
||||
const char *path = qemu_plugin_path_to_binary();
|
||||
uint64_t start_code = qemu_plugin_start_code();
|
||||
uint64_t end_code = qemu_plugin_end_code();
|
||||
uint64_t entry = qemu_plugin_entry_code();
|
||||
fprintf(fp, "0, 0x%lx, 0x%lx, 0x%lx, %s\n",
|
||||
start_code, end_code, entry, path);
|
||||
fprintf(fp, "BB Table: %ld bbs\n", count);
|
||||
}
|
||||
|
||||
static void printf_char_array32(uint32_t data)
|
||||
{
|
||||
const uint8_t *bytes = (const uint8_t *)(&data);
|
||||
fwrite(bytes, sizeof(char), sizeof(data), fp);
|
||||
}
|
||||
|
||||
static void printf_char_array16(uint16_t data)
|
||||
{
|
||||
const uint8_t *bytes = (const uint8_t *)(&data);
|
||||
fwrite(bytes, sizeof(char), sizeof(data), fp);
|
||||
}
|
||||
|
||||
|
||||
static void printf_el(gpointer data, gpointer user_data)
|
||||
{
|
||||
bb_entry_t *bb = (bb_entry_t *)data;
|
||||
if (bb->exec) {
|
||||
printf_char_array32(bb->start);
|
||||
printf_char_array16(bb->size);
|
||||
printf_char_array16(bb->mod_id);
|
||||
}
|
||||
g_free(bb);
|
||||
}
|
||||
|
||||
static void count_block(gpointer data, gpointer user_data)
|
||||
{
|
||||
unsigned long *count = (unsigned long *) user_data;
|
||||
bb_entry_t *bb = (bb_entry_t *)data;
|
||||
if (bb->exec) {
|
||||
*count = *count + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void plugin_exit(qemu_plugin_id_t id, void *p)
|
||||
{
|
||||
unsigned long count = 0;
|
||||
g_mutex_lock(&lock);
|
||||
g_ptr_array_foreach(blocks, count_block, &count);
|
||||
|
||||
/* Print function */
|
||||
printf_header(count);
|
||||
g_ptr_array_foreach(blocks, printf_el, NULL);
|
||||
|
||||
/* Clear */
|
||||
g_ptr_array_free(blocks, true);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
g_mutex_unlock(&lock);
|
||||
}
|
||||
|
||||
static void plugin_init(void)
|
||||
{
|
||||
fp = fopen(file_name, "wb");
|
||||
blocks = g_ptr_array_sized_new(128);
|
||||
}
|
||||
|
||||
static void vcpu_tb_exec(unsigned int cpu_index, void *udata)
|
||||
{
|
||||
bb_entry_t *bb = (bb_entry_t *) udata;
|
||||
|
||||
g_mutex_lock(&lock);
|
||||
bb->exec = true;
|
||||
g_mutex_unlock(&lock);
|
||||
}
|
||||
|
||||
static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
|
||||
{
|
||||
uint64_t pc = qemu_plugin_tb_vaddr(tb);
|
||||
size_t n = qemu_plugin_tb_n_insns(tb);
|
||||
|
||||
g_mutex_lock(&lock);
|
||||
|
||||
bb_entry_t *bb = g_new0(bb_entry_t, 1);
|
||||
for (int i = 0; i < n; i++) {
|
||||
bb->size += qemu_plugin_insn_size(qemu_plugin_tb_get_insn(tb, i));
|
||||
}
|
||||
|
||||
bb->start = pc;
|
||||
bb->mod_id = 0;
|
||||
bb->exec = false;
|
||||
g_ptr_array_add(blocks, bb);
|
||||
|
||||
g_mutex_unlock(&lock);
|
||||
qemu_plugin_register_vcpu_tb_exec_cb(tb, vcpu_tb_exec,
|
||||
QEMU_PLUGIN_CB_NO_REGS,
|
||||
(void *)bb);
|
||||
|
||||
}
|
||||
|
||||
QEMU_PLUGIN_EXPORT
|
||||
int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info,
|
||||
int argc, char **argv)
|
||||
{
|
||||
for (int i = 0; i < argc; i++) {
|
||||
g_autofree char **tokens = g_strsplit(argv[i], "=", 2);
|
||||
if (g_strcmp0(tokens[0], "filename") == 0) {
|
||||
file_name = g_strdup(tokens[1]);
|
||||
}
|
||||
}
|
||||
|
||||
plugin_init();
|
||||
|
||||
qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
|
||||
qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
22
cpu.c
22
cpu.c
@ -377,13 +377,33 @@ static Property cpu_common_props[] = {
|
||||
DEFINE_PROP_LINK("memory", CPUState, memory, TYPE_MEMORY_REGION,
|
||||
MemoryRegion *),
|
||||
#endif
|
||||
DEFINE_PROP_BOOL("start-powered-off", CPUState, start_powered_off, false),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static bool cpu_get_start_powered_off(Object *obj, Error **errp)
|
||||
{
|
||||
CPUState *cpu = CPU(obj);
|
||||
return cpu->start_powered_off;
|
||||
}
|
||||
|
||||
static void cpu_set_start_powered_off(Object *obj, bool value, Error **errp)
|
||||
{
|
||||
CPUState *cpu = CPU(obj);
|
||||
cpu->start_powered_off = value;
|
||||
}
|
||||
|
||||
void cpu_class_init_props(DeviceClass *dc)
|
||||
{
|
||||
ObjectClass *oc = OBJECT_CLASS(dc);
|
||||
|
||||
device_class_set_props(dc, cpu_common_props);
|
||||
/*
|
||||
* We can't use DEFINE_PROP_BOOL in the Property array for this
|
||||
* property, because we want this to be settable after realize.
|
||||
*/
|
||||
object_class_property_add_bool(oc, "start-powered-off",
|
||||
cpu_get_start_powered_off,
|
||||
cpu_set_start_powered_off);
|
||||
}
|
||||
|
||||
void cpu_exec_initfn(CPUState *cpu)
|
||||
|
@ -264,6 +264,19 @@ accepted incorrect commands will return an error. Users should make sure that
|
||||
all arguments passed to ``device_add`` are consistent with the documented
|
||||
property types.
|
||||
|
||||
``query-sgx`` return value member ``section-size`` (since 7.0)
|
||||
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
Member ``section-size`` in return value elements with meta-type ``uint64`` is
|
||||
deprecated. Use ``sections`` instead.
|
||||
|
||||
|
||||
``query-sgx-capabilities`` return value member ``section-size`` (since 7.0)
|
||||
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
Member ``section-size`` in return value elements with meta-type ``uint64`` is
|
||||
deprecated. Use ``sections`` instead.
|
||||
|
||||
System accelerators
|
||||
-------------------
|
||||
|
||||
@ -390,13 +403,6 @@ The above, converted to the current supported format::
|
||||
linux-user mode CPUs
|
||||
--------------------
|
||||
|
||||
``ppc64abi32`` CPUs (since 5.2)
|
||||
'''''''''''''''''''''''''''''''
|
||||
|
||||
The ``ppc64abi32`` architecture has a number of issues which regularly
|
||||
trip up our CI testing and is suspected to be quite broken. For that
|
||||
reason the maintainers strongly suspect no one actually uses it.
|
||||
|
||||
MIPS ``I7200`` CPU (since 5.2)
|
||||
''''''''''''''''''''''''''''''
|
||||
|
||||
@ -441,3 +447,20 @@ nanoMIPS ISA
|
||||
|
||||
The ``nanoMIPS`` ISA has never been upstreamed to any compiler toolchain.
|
||||
As it is hard to generate binaries for it, declare it deprecated.
|
||||
|
||||
Tools
|
||||
-----
|
||||
|
||||
virtiofsd
|
||||
'''''''''
|
||||
|
||||
There is a new Rust implementation of ``virtiofsd`` at
|
||||
``https://gitlab.com/virtio-fs/virtiofsd``;
|
||||
since this is now marked stable, new development should be done on that
|
||||
rather than the existing C version in the QEMU tree.
|
||||
The C version will still accept fixes and patches that
|
||||
are already in development for the moment, but will eventually
|
||||
be deleted from this tree.
|
||||
New deployments should use the Rust version, and existing systems
|
||||
should consider moving to it. The command line and feature set
|
||||
is very close and moving should be simple.
|
||||
|
@ -601,6 +601,27 @@ the upstream Linux kernel in 2018, and it has also been dropped from glibc, so
|
||||
there is no new Linux development taking place with this architecture. For
|
||||
running the old binaries, you can use older versions of QEMU.
|
||||
|
||||
``ppc64abi32`` CPUs (removed in 7.0)
|
||||
''''''''''''''''''''''''''''''''''''
|
||||
|
||||
The ``ppc64abi32`` architecture has a number of issues which regularly
|
||||
tripped up the CI testing and was suspected to be quite broken. For that
|
||||
reason the maintainers strongly suspected no one actually used it.
|
||||
|
||||
|
||||
TCG introspection features
|
||||
--------------------------
|
||||
|
||||
TCG trace-events (since 6.2)
|
||||
''''''''''''''''''''''''''''
|
||||
|
||||
The ability to add new TCG trace points had bit rotted and as the
|
||||
feature can be replicated with TCG plugins it was removed. If
|
||||
any user is currently using this feature and needs help with
|
||||
converting to using TCG plugins they should contact the qemu-devel
|
||||
mailing list.
|
||||
|
||||
|
||||
System emulator devices
|
||||
-----------------------
|
||||
|
||||
|
@ -98,7 +98,7 @@ default_role = 'any'
|
||||
|
||||
# General information about the project.
|
||||
project = u'QEMU'
|
||||
copyright = u'2021, The QEMU Project Developers'
|
||||
copyright = u'2022, The QEMU Project Developers'
|
||||
author = u'The QEMU Project Developers'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
|
@ -1630,6 +1630,9 @@ The following files are generated:
|
||||
``$(prefix)qapi-commands.h``
|
||||
Function prototypes for the QMP commands specified in the schema
|
||||
|
||||
``$(prefix)qapi-commands.trace-events``
|
||||
Trace event declarations, see :ref:`tracing`.
|
||||
|
||||
``$(prefix)qapi-init-commands.h``
|
||||
Command initialization prototype
|
||||
|
||||
@ -1650,6 +1653,13 @@ Example::
|
||||
void qmp_marshal_my_command(QDict *args, QObject **ret, Error **errp);
|
||||
|
||||
#endif /* EXAMPLE_QAPI_COMMANDS_H */
|
||||
|
||||
$ cat qapi-generated/example-qapi-commands.trace-events
|
||||
# AUTOMATICALLY GENERATED, DO NOT MODIFY
|
||||
|
||||
qmp_enter_my_command(const char *json) "%s"
|
||||
qmp_exit_my_command(const char *result, bool succeeded) "%s %d"
|
||||
|
||||
$ cat qapi-generated/example-qapi-commands.c
|
||||
[Uninteresting stuff omitted...]
|
||||
|
||||
@ -1689,14 +1699,27 @@ Example::
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (trace_event_get_state_backends(TRACE_QMP_ENTER_MY_COMMAND)) {
|
||||
g_autoptr(GString) req_json = qobject_to_json(QOBJECT(args));
|
||||
|
||||
trace_qmp_enter_my_command(req_json->str);
|
||||
}
|
||||
|
||||
retval = qmp_my_command(arg.arg1, &err);
|
||||
error_propagate(errp, err);
|
||||
if (err) {
|
||||
trace_qmp_exit_my_command(error_get_pretty(err), false);
|
||||
error_propagate(errp, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
qmp_marshal_output_UserDefOne(retval, ret, errp);
|
||||
|
||||
if (trace_event_get_state_backends(TRACE_QMP_EXIT_MY_COMMAND)) {
|
||||
g_autoptr(GString) ret_json = qobject_to_json(*ret);
|
||||
|
||||
trace_qmp_exit_my_command(ret_json->str, true);
|
||||
}
|
||||
|
||||
out:
|
||||
visit_free(v);
|
||||
v = qapi_dealloc_visitor_new();
|
||||
|
@ -12,6 +12,10 @@ patches before submitting.
|
||||
Formatting and style
|
||||
********************
|
||||
|
||||
The repository includes a ``.editorconfig`` file which can help with
|
||||
getting the right settings for your preferred $EDITOR. See
|
||||
`<https://editorconfig.org/>`_ for details.
|
||||
|
||||
Whitespace
|
||||
==========
|
||||
|
||||
|
@ -1324,7 +1324,7 @@ for the architecture in question, for example::
|
||||
|
||||
$(configure) --cross-cc-aarch64=aarch64-cc
|
||||
|
||||
There is also a ``--cross-cc-flags-ARCH`` flag in case additional
|
||||
There is also a ``--cross-cc-cflags-ARCH`` flag in case additional
|
||||
compiler flags are needed to build for a given target.
|
||||
|
||||
If you have the ability to run containers as the user the build system
|
||||
|
@ -1,3 +1,5 @@
|
||||
.. _tracing:
|
||||
|
||||
=======
|
||||
Tracing
|
||||
=======
|
||||
@ -411,88 +413,3 @@ disabled, this check will have no performance impact.
|
||||
return ptr;
|
||||
}
|
||||
|
||||
"tcg"
|
||||
-----
|
||||
|
||||
Guest code generated by TCG can be traced by defining an event with the "tcg"
|
||||
event property. Internally, this property generates two events:
|
||||
"<eventname>_trans" to trace the event at translation time, and
|
||||
"<eventname>_exec" to trace the event at execution time.
|
||||
|
||||
Instead of using these two events, you should instead use the function
|
||||
"trace_<eventname>_tcg" during translation (TCG code generation). This function
|
||||
will automatically call "trace_<eventname>_trans", and will generate the
|
||||
necessary TCG code to call "trace_<eventname>_exec" during guest code execution.
|
||||
|
||||
Events with the "tcg" property can be declared in the "trace-events" file with a
|
||||
mix of native and TCG types, and "trace_<eventname>_tcg" will gracefully forward
|
||||
them to the "<eventname>_trans" and "<eventname>_exec" events. Since TCG values
|
||||
are not known at translation time, these are ignored by the "<eventname>_trans"
|
||||
event. Because of this, the entry in the "trace-events" file needs two printing
|
||||
formats (separated by a comma)::
|
||||
|
||||
tcg foo(uint8_t a1, TCGv_i32 a2) "a1=%d", "a1=%d a2=%d"
|
||||
|
||||
For example::
|
||||
|
||||
#include "trace-tcg.h"
|
||||
|
||||
void some_disassembly_func (...)
|
||||
{
|
||||
uint8_t a1 = ...;
|
||||
TCGv_i32 a2 = ...;
|
||||
trace_foo_tcg(a1, a2);
|
||||
}
|
||||
|
||||
This will immediately call::
|
||||
|
||||
void trace_foo_trans(uint8_t a1);
|
||||
|
||||
and will generate the TCG code to call::
|
||||
|
||||
void trace_foo(uint8_t a1, uint32_t a2);
|
||||
|
||||
"vcpu"
|
||||
------
|
||||
|
||||
Identifies events that trace vCPU-specific information. It implicitly adds a
|
||||
"CPUState*" argument, and extends the tracing print format to show the vCPU
|
||||
information. If used together with the "tcg" property, it adds a second
|
||||
"TCGv_env" argument that must point to the per-target global TCG register that
|
||||
points to the vCPU when guest code is executed (usually the "cpu_env" variable).
|
||||
|
||||
The "tcg" and "vcpu" properties are currently only honored in the root
|
||||
./trace-events file.
|
||||
|
||||
The following example events::
|
||||
|
||||
foo(uint32_t a) "a=%x"
|
||||
vcpu bar(uint32_t a) "a=%x"
|
||||
tcg vcpu baz(uint32_t a) "a=%x", "a=%x"
|
||||
|
||||
Can be used as::
|
||||
|
||||
#include "trace-tcg.h"
|
||||
|
||||
CPUArchState *env;
|
||||
TCGv_ptr cpu_env;
|
||||
|
||||
void some_disassembly_func(...)
|
||||
{
|
||||
/* trace emitted at this point */
|
||||
trace_foo(0xd1);
|
||||
/* trace emitted at this point */
|
||||
trace_bar(env_cpu(env), 0xd2);
|
||||
/* trace emitted at this point (env) and when guest code is executed (cpu_env) */
|
||||
trace_baz_tcg(env_cpu(env), cpu_env, 0xd3);
|
||||
}
|
||||
|
||||
If the translating vCPU has address 0xc1 and code is later executed by vCPU
|
||||
0xc2, this would be an example output::
|
||||
|
||||
// at guest code translation
|
||||
foo a=0xd1
|
||||
bar cpu=0xc1 a=0xd2
|
||||
baz_trans cpu=0xc1 a=0xd3
|
||||
// at guest code execution
|
||||
baz_exec cpu=0xc2 a=0xd3
|
||||
|
@ -19,10 +19,10 @@ Running a Confidential Guest
|
||||
|
||||
To run a confidential guest you need to add two command line parameters:
|
||||
|
||||
1. Use "-object" to create a "confidential guest support" object. The
|
||||
1. Use ``-object`` to create a "confidential guest support" object. The
|
||||
type and parameters will vary with the specific mechanism to be
|
||||
used
|
||||
2. Set the "confidential-guest-support" machine parameter to the ID of
|
||||
2. Set the ``confidential-guest-support`` machine parameter to the ID of
|
||||
the object from (1).
|
||||
|
||||
Example (for AMD SEV)::
|
||||
@ -37,13 +37,8 @@ Supported mechanisms
|
||||
|
||||
Currently supported confidential guest mechanisms are:
|
||||
|
||||
AMD Secure Encrypted Virtualization (SEV)
|
||||
docs/amd-memory-encryption.txt
|
||||
|
||||
POWER Protected Execution Facility (PEF)
|
||||
docs/papr-pef.txt
|
||||
|
||||
s390x Protected Virtualization (PV)
|
||||
docs/system/s390x/protvirt.rst
|
||||
* AMD Secure Encrypted Virtualization (SEV) (see :doc:`i386/amd-memory-encryption`)
|
||||
* POWER Protected Execution Facility (PEF) (see :ref:`power-papr-protected-execution-facility-pef`)
|
||||
* s390x Protected Virtualization (PV) (see :doc:`s390x/protvirt`)
|
||||
|
||||
Other mechanisms may be supported in future.
|
@ -1,3 +1,6 @@
|
||||
AMD Secure Encrypted Virtualization (SEV)
|
||||
=========================================
|
||||
|
||||
Secure Encrypted Virtualization (SEV) is a feature found on AMD processors.
|
||||
|
||||
SEV is an extension to the AMD-V architecture which supports running encrypted
|
||||
@ -24,17 +27,18 @@ the hypervisor to satisfy the requested function.
|
||||
|
||||
Launching
|
||||
---------
|
||||
|
||||
Boot images (such as bios) must be encrypted before a guest can be booted. The
|
||||
MEMORY_ENCRYPT_OP ioctl provides commands to encrypt the images: LAUNCH_START,
|
||||
LAUNCH_UPDATE_DATA, LAUNCH_MEASURE and LAUNCH_FINISH. These four commands
|
||||
``MEMORY_ENCRYPT_OP`` ioctl provides commands to encrypt the images: ``LAUNCH_START``,
|
||||
``LAUNCH_UPDATE_DATA``, ``LAUNCH_MEASURE`` and ``LAUNCH_FINISH``. These four commands
|
||||
together generate a fresh memory encryption key for the VM, encrypt the boot
|
||||
images and provide a measurement than can be used as an attestation of a
|
||||
successful launch.
|
||||
|
||||
For a SEV-ES guest, the LAUNCH_UPDATE_VMSA command is also used to encrypt the
|
||||
For a SEV-ES guest, the ``LAUNCH_UPDATE_VMSA`` command is also used to encrypt the
|
||||
guest register state, or VM save area (VMSA), for all of the guest vCPUs.
|
||||
|
||||
LAUNCH_START is called first to create a cryptographic launch context within
|
||||
``LAUNCH_START`` is called first to create a cryptographic launch context within
|
||||
the firmware. To create this context, guest owner must provide a guest policy,
|
||||
its public Diffie-Hellman key (PDH) and session parameters. These inputs
|
||||
should be treated as a binary blob and must be passed as-is to the SEV firmware.
|
||||
@ -45,37 +49,37 @@ in bad measurement). The guest policy is a 4-byte data structure containing
|
||||
several flags that restricts what can be done on a running SEV guest.
|
||||
See KM Spec section 3 and 6.2 for more details.
|
||||
|
||||
The guest policy can be provided via the 'policy' property (see below)
|
||||
The guest policy can be provided via the ``policy`` property::
|
||||
|
||||
# ${QEMU} \
|
||||
# ${QEMU} \
|
||||
sev-guest,id=sev0,policy=0x1...\
|
||||
|
||||
Setting the "SEV-ES required" policy bit (bit 2) will launch the guest as a
|
||||
SEV-ES guest (see below)
|
||||
SEV-ES guest::
|
||||
|
||||
# ${QEMU} \
|
||||
# ${QEMU} \
|
||||
sev-guest,id=sev0,policy=0x5...\
|
||||
|
||||
The guest owner provided DH certificate and session parameters will be used to
|
||||
establish a cryptographic session with the guest owner to negotiate keys used
|
||||
for the attestation.
|
||||
|
||||
The DH certificate and session blob can be provided via the 'dh-cert-file' and
|
||||
'session-file' properties (see below)
|
||||
The DH certificate and session blob can be provided via the ``dh-cert-file`` and
|
||||
``session-file`` properties::
|
||||
|
||||
# ${QEMU} \
|
||||
# ${QEMU} \
|
||||
sev-guest,id=sev0,dh-cert-file=<file1>,session-file=<file2>
|
||||
|
||||
LAUNCH_UPDATE_DATA encrypts the memory region using the cryptographic context
|
||||
created via the LAUNCH_START command. If required, this command can be called
|
||||
``LAUNCH_UPDATE_DATA`` encrypts the memory region using the cryptographic context
|
||||
created via the ``LAUNCH_START`` command. If required, this command can be called
|
||||
multiple times to encrypt different memory regions. The command also calculates
|
||||
the measurement of the memory contents as it encrypts.
|
||||
|
||||
LAUNCH_UPDATE_VMSA encrypts all the vCPU VMSAs for a SEV-ES guest using the
|
||||
cryptographic context created via the LAUNCH_START command. The command also
|
||||
``LAUNCH_UPDATE_VMSA`` encrypts all the vCPU VMSAs for a SEV-ES guest using the
|
||||
cryptographic context created via the ``LAUNCH_START`` command. The command also
|
||||
calculates the measurement of the VMSAs as it encrypts them.
|
||||
|
||||
LAUNCH_MEASURE can be used to retrieve the measurement of encrypted memory and,
|
||||
``LAUNCH_MEASURE`` can be used to retrieve the measurement of encrypted memory and,
|
||||
for a SEV-ES guest, encrypted VMSAs. This measurement is a signature of the
|
||||
memory contents and, for a SEV-ES guest, the VMSA contents, that can be sent
|
||||
to the guest owner as an attestation that the memory and VMSAs were encrypted
|
||||
@ -85,27 +89,28 @@ Since the guest owner knows the initial contents of the guest at boot, the
|
||||
attestation measurement can be verified by comparing it to what the guest owner
|
||||
expects.
|
||||
|
||||
LAUNCH_FINISH finalizes the guest launch and destroys the cryptographic
|
||||
``LAUNCH_FINISH`` finalizes the guest launch and destroys the cryptographic
|
||||
context.
|
||||
|
||||
See SEV KM API Spec [1] 'Launching a guest' usage flow (Appendix A) for the
|
||||
See SEV KM API Spec ([SEVKM]_) 'Launching a guest' usage flow (Appendix A) for the
|
||||
complete flow chart.
|
||||
|
||||
To launch a SEV guest
|
||||
To launch a SEV guest::
|
||||
|
||||
# ${QEMU} \
|
||||
# ${QEMU} \
|
||||
-machine ...,confidential-guest-support=sev0 \
|
||||
-object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=1
|
||||
|
||||
To launch a SEV-ES guest
|
||||
To launch a SEV-ES guest::
|
||||
|
||||
# ${QEMU} \
|
||||
# ${QEMU} \
|
||||
-machine ...,confidential-guest-support=sev0 \
|
||||
-object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=1,policy=0x5
|
||||
|
||||
An SEV-ES guest has some restrictions as compared to a SEV guest. Because the
|
||||
guest register state is encrypted and cannot be updated by the VMM/hypervisor,
|
||||
a SEV-ES guest:
|
||||
|
||||
- Does not support SMM - SMM support requires updating the guest register
|
||||
state.
|
||||
- Does not support reboot - a system reset requires updating the guest register
|
||||
@ -114,35 +119,42 @@ a SEV-ES guest:
|
||||
manage booting APs.
|
||||
|
||||
Debugging
|
||||
-----------
|
||||
---------
|
||||
|
||||
Since the memory contents of a SEV guest are encrypted, hypervisor access to
|
||||
the guest memory will return cipher text. If the guest policy allows debugging,
|
||||
then a hypervisor can use the DEBUG_DECRYPT and DEBUG_ENCRYPT commands to access
|
||||
the guest memory region for debug purposes. This is not supported in QEMU yet.
|
||||
|
||||
Snapshot/Restore
|
||||
-----------------
|
||||
----------------
|
||||
|
||||
TODO
|
||||
|
||||
Live Migration
|
||||
----------------
|
||||
---------------
|
||||
|
||||
TODO
|
||||
|
||||
References
|
||||
-----------------
|
||||
----------
|
||||
|
||||
AMD Memory Encryption whitepaper:
|
||||
https://developer.amd.com/wordpress/media/2013/12/AMD_Memory_Encryption_Whitepaper_v7-Public.pdf
|
||||
`AMD Memory Encryption whitepaper
|
||||
<https://developer.amd.com/wordpress/media/2013/12/AMD_Memory_Encryption_Whitepaper_v7-Public.pdf>`_
|
||||
|
||||
Secure Encrypted Virtualization Key Management:
|
||||
[1] http://developer.amd.com/wordpress/media/2017/11/55766_SEV-KM-API_Specification.pdf
|
||||
.. [SEVKM] `Secure Encrypted Virtualization Key Management
|
||||
<http://developer.amd.com/wordpress/media/2017/11/55766_SEV-KM-API_Specification.pdf>`_
|
||||
|
||||
KVM Forum slides:
|
||||
http://www.linux-kvm.org/images/7/74/02x08A-Thomas_Lendacky-AMDs_Virtualizatoin_Memory_Encryption_Technology.pdf
|
||||
https://www.linux-kvm.org/images/9/94/Extending-Secure-Encrypted-Virtualization-with-SEV-ES-Thomas-Lendacky-AMD.pdf
|
||||
|
||||
AMD64 Architecture Programmer's Manual:
|
||||
http://support.amd.com/TechDocs/24593.pdf
|
||||
SME is section 7.10
|
||||
SEV is section 15.34
|
||||
SEV-ES is section 15.35
|
||||
* `AMD’s Virtualization Memory Encryption (2016)
|
||||
<http://www.linux-kvm.org/images/7/74/02x08A-Thomas_Lendacky-AMDs_Virtualizatoin_Memory_Encryption_Technology.pdf>`_
|
||||
* `Extending Secure Encrypted Virtualization With SEV-ES (2018)
|
||||
<https://www.linux-kvm.org/images/9/94/Extending-Secure-Encrypted-Virtualization-with-SEV-ES-Thomas-Lendacky-AMD.pdf>`_
|
||||
|
||||
`AMD64 Architecture Programmer's Manual:
|
||||
<http://support.amd.com/TechDocs/24593.pdf>`_
|
||||
|
||||
* SME is section 7.10
|
||||
* SEV is section 15.34
|
||||
* SEV-ES is section 15.35
|
@ -34,3 +34,4 @@ or Hypervisor.Framework.
|
||||
targets
|
||||
security
|
||||
multi-process
|
||||
confidential-guest-support
|
||||
|
@ -224,6 +224,8 @@ nested. Combinations not shown in the table are not available.
|
||||
.. [3] Introduced on Power10 machines.
|
||||
|
||||
|
||||
.. _power-papr-protected-execution-facility-pef:
|
||||
|
||||
POWER (PAPR) Protected Execution Facility (PEF)
|
||||
-----------------------------------------------
|
||||
|
||||
|
@ -23,9 +23,9 @@ The ``virt`` machine supports the following devices:
|
||||
* 1 generic PCIe host bridge
|
||||
* The fw_cfg device that allows a guest to obtain data from QEMU
|
||||
|
||||
Note that the default CPU is a generic RV32GC/RV64GC. Optional extensions
|
||||
can be enabled via command line parameters, e.g.: ``-cpu rv64,x-h=true``
|
||||
enables the hypervisor extension for RV64.
|
||||
The hypervisor extension has been enabled for the default CPU, so virtual
|
||||
machines with hypervisor extension can simply be used without explicitly
|
||||
declaring.
|
||||
|
||||
Hardware configuration information
|
||||
----------------------------------
|
||||
|
@ -28,6 +28,7 @@ Architectural features
|
||||
i386/cpu
|
||||
i386/kvm-pv
|
||||
i386/sgx
|
||||
i386/amd-memory-encryption
|
||||
|
||||
.. _pcsys_005freq:
|
||||
|
||||
|
@ -463,7 +463,7 @@ Command description:
|
||||
``--skip-broken-bitmaps`` is also specified to copy only the
|
||||
consistent bitmaps.
|
||||
|
||||
.. option:: create [--object OBJECTDEF] [-q] [-f FMT] [-b BACKING_FILE] [-F BACKING_FMT] [-u] [-o OPTIONS] FILENAME [SIZE]
|
||||
.. option:: create [--object OBJECTDEF] [-q] [-f FMT] [-b BACKING_FILE [-F BACKING_FMT]] [-u] [-o OPTIONS] FILENAME [SIZE]
|
||||
|
||||
Create the new disk image *FILENAME* of size *SIZE* and format
|
||||
*FMT*. Depending on the file format, you can add one or more *OPTIONS*
|
||||
|
@ -76,7 +76,7 @@ Standard options:
|
||||
.. option:: --export [type=]nbd,id=<id>,node-name=<node-name>[,name=<export-name>][,writable=on|off][,bitmap=<name>]
|
||||
--export [type=]vhost-user-blk,id=<id>,node-name=<node-name>,addr.type=unix,addr.path=<socket-path>[,writable=on|off][,logical-block-size=<block-size>][,num-queues=<num-queues>]
|
||||
--export [type=]vhost-user-blk,id=<id>,node-name=<node-name>,addr.type=fd,addr.str=<fd>[,writable=on|off][,logical-block-size=<block-size>][,num-queues=<num-queues>]
|
||||
--export [type=]fuse,id=<id>,node-name=<node-name>,mountpoint=<file>[,growable=on|off][,writable=on|off]
|
||||
--export [type=]fuse,id=<id>,node-name=<node-name>,mountpoint=<file>[,growable=on|off][,writable=on|off][,allow-other=on|off|auto]
|
||||
|
||||
is a block export definition. ``node-name`` is the block node that should be
|
||||
exported. ``writable`` determines whether or not the export allows write
|
||||
@ -103,7 +103,12 @@ Standard options:
|
||||
mounted). Consequently, applications that have opened the given file before
|
||||
the export became active will continue to see its original content. If
|
||||
``growable`` is set, writes after the end of the exported file will grow the
|
||||
block node to fit.
|
||||
block node to fit. The ``allow-other`` option controls whether users other
|
||||
than the user running the process will be allowed to access the export. Note
|
||||
that enabling this option as a non-root user requires enabling the
|
||||
user_allow_other option in the global fuse.conf configuration file. Setting
|
||||
``allow-other`` to auto (the default) will try enabling this option, and on
|
||||
error fall back to disabling it.
|
||||
|
||||
.. option:: --monitor MONITORDEF
|
||||
|
||||
|
@ -166,7 +166,6 @@ Other binaries
|
||||
|
||||
- user mode (PowerPC)
|
||||
|
||||
* ``qemu-ppc64abi32`` TODO.
|
||||
* ``qemu-ppc64`` TODO.
|
||||
* ``qemu-ppc`` TODO.
|
||||
|
||||
|
@ -10,6 +10,7 @@ config ACPI_X86
|
||||
select ACPI_HMAT
|
||||
select ACPI_PIIX4
|
||||
select ACPI_PCIHP
|
||||
select ACPI_ERST
|
||||
|
||||
config ACPI_X86_ICH
|
||||
bool
|
||||
@ -60,3 +61,8 @@ config ACPI_HW_REDUCED
|
||||
select ACPI
|
||||
select ACPI_MEMORY_HOTPLUG
|
||||
select ACPI_NVDIMM
|
||||
|
||||
config ACPI_ERST
|
||||
bool
|
||||
default y
|
||||
depends on ACPI && PCI
|
||||
|
@ -1724,9 +1724,9 @@ void acpi_table_begin(AcpiTable *desc, GArray *array)
|
||||
build_append_int_noprefix(array, 0, 4); /* Length */
|
||||
build_append_int_noprefix(array, desc->rev, 1); /* Revision */
|
||||
build_append_int_noprefix(array, 0, 1); /* Checksum */
|
||||
build_append_padded_str(array, desc->oem_id, 6, ' '); /* OEMID */
|
||||
build_append_padded_str(array, desc->oem_id, 6, '\0'); /* OEMID */
|
||||
/* OEM Table ID */
|
||||
build_append_padded_str(array, desc->oem_table_id, 8, ' ');
|
||||
build_append_padded_str(array, desc->oem_table_id, 8, '\0');
|
||||
build_append_int_noprefix(array, 1, 4); /* OEM Revision */
|
||||
g_array_append_vals(array, ACPI_BUILD_APPNAME8, 4); /* Creator ID */
|
||||
build_append_int_noprefix(array, 1, 4); /* Creator Revision */
|
||||
|
@ -297,7 +297,6 @@ static const VMStateDescription vmstate_cpuhp_sts = {
|
||||
.name = "CPU hotplug device state",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_BOOL(is_inserting, AcpiCpuStatus),
|
||||
VMSTATE_BOOL(is_removing, AcpiCpuStatus),
|
||||
@ -311,7 +310,6 @@ const VMStateDescription vmstate_cpu_hotplug = {
|
||||
.name = "CPU hotplug state",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(selector, CPUHotplugState),
|
||||
VMSTATE_UINT8(command, CPUHotplugState),
|
||||
|
1051
hw/acpi/erst.c
Normal file
1051
hw/acpi/erst.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -163,7 +163,6 @@ static const VMStateDescription vmstate_memhp_state = {
|
||||
.name = "ich9_pm/memhp",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.needed = vmstate_test_use_memhp,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, ICH9LPCPMRegs),
|
||||
@ -181,7 +180,6 @@ static const VMStateDescription vmstate_tco_io_state = {
|
||||
.name = "ich9_pm/tco",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.needed = vmstate_test_use_tco,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_STRUCT(tco_regs, ICH9LPCPMRegs, 1, vmstate_tco_io_sts,
|
||||
@ -208,7 +206,6 @@ static const VMStateDescription vmstate_cpuhp_state = {
|
||||
.name = "ich9_pm/cpuhp",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.needed = vmstate_test_use_cpuhp,
|
||||
.pre_load = vmstate_cpuhp_pre_load,
|
||||
.fields = (VMStateField[]) {
|
||||
|
@ -318,7 +318,6 @@ static const VMStateDescription vmstate_memhp_sts = {
|
||||
.name = "memory hotplug device state",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_BOOL(is_enabled, MemStatus),
|
||||
VMSTATE_BOOL(is_inserting, MemStatus),
|
||||
@ -332,7 +331,6 @@ const VMStateDescription vmstate_memory_hotplug = {
|
||||
.name = "memory hotplug state",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(selector, MemHotplugState),
|
||||
VMSTATE_STRUCT_VARRAY_POINTER_UINT32(devs, MemHotplugState, dev_count,
|
||||
|
@ -22,6 +22,7 @@ acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_true: files('pcihp.c'))
|
||||
acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_false: files('acpi-pci-hotplug-stub.c'))
|
||||
acpi_ss.add(when: 'CONFIG_ACPI_VIOT', if_true: files('viot.c'))
|
||||
acpi_ss.add(when: 'CONFIG_ACPI_X86_ICH', if_true: files('ich9.c', 'tco.c'))
|
||||
acpi_ss.add(when: 'CONFIG_ACPI_ERST', if_true: files('erst.c'))
|
||||
acpi_ss.add(when: 'CONFIG_IPMI', if_true: files('ipmi.c'), if_false: files('ipmi-stub.c'))
|
||||
acpi_ss.add(when: 'CONFIG_PC', if_false: files('acpi-x86-stub.c'))
|
||||
acpi_ss.add(when: 'CONFIG_TPM', if_true: files('tpm.c'))
|
||||
|
@ -230,7 +230,6 @@ static const VMStateDescription vmstate_memhp_state = {
|
||||
.name = "piix4_pm/memhp",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.needed = vmstate_test_use_memhp,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, PIIX4PMState),
|
||||
@ -255,7 +254,6 @@ static const VMStateDescription vmstate_cpuhp_state = {
|
||||
.name = "piix4_pm/cpuhp",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.needed = vmstate_test_use_cpuhp,
|
||||
.pre_load = vmstate_cpuhp_pre_load,
|
||||
.fields = (VMStateField[]) {
|
||||
|
@ -239,7 +239,6 @@ const VMStateDescription vmstate_tco_io_sts = {
|
||||
.name = "tco io device status",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT16(tco.rld, TCOIORegs),
|
||||
VMSTATE_UINT8(tco.din, TCOIORegs),
|
||||
|
@ -55,3 +55,18 @@ piix4_gpe_writeb(uint64_t addr, unsigned width, uint64_t val) "addr: 0x%" PRIx64
|
||||
# tco.c
|
||||
tco_timer_reload(int ticks, int msec) "ticks=%d (%d ms)"
|
||||
tco_timer_expired(int timeouts_no, bool strap, bool no_reboot) "timeouts_no=%d no_reboot=%d/%d"
|
||||
|
||||
# erst.c
|
||||
acpi_erst_reg_write(uint64_t addr, uint64_t val, unsigned size) "addr: 0x%04" PRIx64 " <== 0x%016" PRIx64 " (size: %u)"
|
||||
acpi_erst_reg_read(uint64_t addr, uint64_t val, unsigned size) " addr: 0x%04" PRIx64 " ==> 0x%016" PRIx64 " (size: %u)"
|
||||
acpi_erst_mem_write(uint64_t addr, uint64_t val, unsigned size) "addr: 0x%06" PRIx64 " <== 0x%016" PRIx64 " (size: %u)"
|
||||
acpi_erst_mem_read(uint64_t addr, uint64_t val, unsigned size) " addr: 0x%06" PRIx64 " ==> 0x%016" PRIx64 " (size: %u)"
|
||||
acpi_erst_pci_bar_0(uint64_t addr) "BAR0: 0x%016" PRIx64
|
||||
acpi_erst_pci_bar_1(uint64_t addr) "BAR1: 0x%016" PRIx64
|
||||
acpi_erst_realizefn_in(void)
|
||||
acpi_erst_realizefn_out(unsigned size) "total nvram size %u bytes"
|
||||
acpi_erst_reset_in(unsigned record_count) "record_count %u"
|
||||
acpi_erst_reset_out(unsigned record_count) "record_count %u"
|
||||
acpi_erst_post_load(void *header, unsigned slot_size) "header: 0x%p slot_size %u"
|
||||
acpi_erst_class_init_in(void)
|
||||
acpi_erst_class_init_out(void)
|
||||
|
@ -235,11 +235,10 @@ static void allwinner_h3_realize(DeviceState *dev, Error **errp)
|
||||
/* CPUs */
|
||||
for (i = 0; i < AW_H3_NUM_CPUS; i++) {
|
||||
|
||||
/* Provide Power State Coordination Interface */
|
||||
qdev_prop_set_int32(DEVICE(&s->cpus[i]), "psci-conduit",
|
||||
QEMU_PSCI_CONDUIT_SMC);
|
||||
|
||||
/* Disable secondary CPUs */
|
||||
/*
|
||||
* Disable secondary CPUs. Guest EL3 firmware will start
|
||||
* them via CPU reset control registers.
|
||||
*/
|
||||
qdev_prop_set_bit(DEVICE(&s->cpus[i]), "start-powered-off",
|
||||
i > 0);
|
||||
|
||||
|
@ -520,8 +520,8 @@ static const VMStateDescription vmstate_armv7m = {
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_CLOCK(refclk, SysTickState),
|
||||
VMSTATE_CLOCK(cpuclk, SysTickState),
|
||||
VMSTATE_CLOCK(refclk, ARMv7MState),
|
||||
VMSTATE_CLOCK(cpuclk, ARMv7MState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
@ -431,7 +431,6 @@ static void aspeed_machine_init(MachineState *machine)
|
||||
|
||||
aspeed_board_binfo.ram_size = machine->ram_size;
|
||||
aspeed_board_binfo.loader_start = sc->memmap[ASPEED_DEV_SDRAM];
|
||||
aspeed_board_binfo.nb_cpus = sc->num_cpus;
|
||||
|
||||
if (amc->i2c_init) {
|
||||
amc->i2c_init(bmc);
|
||||
|
@ -29,7 +29,7 @@ static const hwaddr aspeed_soc_ast2600_memmap[] = {
|
||||
[ASPEED_DEV_PWM] = 0x1E610000,
|
||||
[ASPEED_DEV_FMC] = 0x1E620000,
|
||||
[ASPEED_DEV_SPI1] = 0x1E630000,
|
||||
[ASPEED_DEV_SPI2] = 0x1E641000,
|
||||
[ASPEED_DEV_SPI2] = 0x1E631000,
|
||||
[ASPEED_DEV_EHCI1] = 0x1E6A1000,
|
||||
[ASPEED_DEV_EHCI2] = 0x1E6A3000,
|
||||
[ASPEED_DEV_MII1] = 0x1E650000,
|
||||
|
107
hw/arm/boot.c
107
hw/arm/boot.c
@ -478,12 +478,13 @@ static void fdt_add_psci_node(void *fdt)
|
||||
}
|
||||
|
||||
/*
|
||||
* If /psci node is present in provided DTB, assume that no fixup
|
||||
* is necessary and all PSCI configuration should be taken as-is
|
||||
* A pre-existing /psci node might specify function ID values
|
||||
* that don't match QEMU's PSCI implementation. Delete the whole
|
||||
* node and put our own in instead.
|
||||
*/
|
||||
rc = fdt_path_offset(fdt, "/psci");
|
||||
if (rc >= 0) {
|
||||
return;
|
||||
qemu_fdt_nop_node(fdt, "/psci");
|
||||
}
|
||||
|
||||
qemu_fdt_add_subnode(fdt, "/psci");
|
||||
@ -804,7 +805,7 @@ static void do_cpu_reset(void *opaque)
|
||||
set_kernel_args(info, as);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else if (info->secondary_cpu_reset_hook) {
|
||||
info->secondary_cpu_reset_hook(cpu, info);
|
||||
}
|
||||
}
|
||||
@ -1030,16 +1031,6 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu,
|
||||
elf_machine = EM_ARM;
|
||||
}
|
||||
|
||||
if (!info->secondary_cpu_reset_hook) {
|
||||
info->secondary_cpu_reset_hook = default_reset_secondary;
|
||||
}
|
||||
if (!info->write_secondary_boot) {
|
||||
info->write_secondary_boot = default_write_secondary;
|
||||
}
|
||||
|
||||
if (info->nb_cpus == 0)
|
||||
info->nb_cpus = 1;
|
||||
|
||||
/* Assume that raw images are linux kernels, and ELF images are not. */
|
||||
kernel_size = arm_load_elf(info, &elf_entry, &image_low_addr,
|
||||
&image_high_addr, elf_machine, as);
|
||||
@ -1216,9 +1207,6 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu,
|
||||
write_bootloader("bootloader", info->loader_start,
|
||||
primary_loader, fixupcontext, as);
|
||||
|
||||
if (info->nb_cpus > 1) {
|
||||
info->write_secondary_boot(cpu, info);
|
||||
}
|
||||
if (info->write_board_setup) {
|
||||
info->write_board_setup(cpu, info);
|
||||
}
|
||||
@ -1299,6 +1287,9 @@ void arm_load_kernel(ARMCPU *cpu, MachineState *ms, struct arm_boot_info *info)
|
||||
{
|
||||
CPUState *cs;
|
||||
AddressSpace *as = arm_boot_address_space(cpu, info);
|
||||
int boot_el;
|
||||
CPUARMState *env = &cpu->env;
|
||||
int nb_cpus = 0;
|
||||
|
||||
/*
|
||||
* CPU objects (unlike devices) are not automatically reset on system
|
||||
@ -1308,6 +1299,7 @@ void arm_load_kernel(ARMCPU *cpu, MachineState *ms, struct arm_boot_info *info)
|
||||
*/
|
||||
for (cs = first_cpu; cs; cs = CPU_NEXT(cs)) {
|
||||
qemu_register_reset(do_cpu_reset, ARM_CPU(cs));
|
||||
nb_cpus++;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1329,6 +1321,87 @@ void arm_load_kernel(ARMCPU *cpu, MachineState *ms, struct arm_boot_info *info)
|
||||
arm_setup_direct_kernel_boot(cpu, info);
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable the PSCI conduit if it is set up to target the same
|
||||
* or a lower EL than the one we're going to start the guest code in.
|
||||
* This logic needs to agree with the code in do_cpu_reset() which
|
||||
* decides whether we're going to boot the guest in the highest
|
||||
* supported exception level or in a lower one.
|
||||
*/
|
||||
|
||||
/*
|
||||
* If PSCI is enabled, then SMC calls all go to the PSCI handler and
|
||||
* are never emulated to trap into guest code. It therefore does not
|
||||
* make sense for the board to have a setup code fragment that runs
|
||||
* in Secure, because this will probably need to itself issue an SMC of some
|
||||
* kind as part of its operation.
|
||||
*/
|
||||
assert(info->psci_conduit == QEMU_PSCI_CONDUIT_DISABLED ||
|
||||
!info->secure_board_setup);
|
||||
|
||||
/* Boot into highest supported EL ... */
|
||||
if (arm_feature(env, ARM_FEATURE_EL3)) {
|
||||
boot_el = 3;
|
||||
} else if (arm_feature(env, ARM_FEATURE_EL2)) {
|
||||
boot_el = 2;
|
||||
} else {
|
||||
boot_el = 1;
|
||||
}
|
||||
/* ...except that if we're booting Linux we adjust the EL we boot into */
|
||||
if (info->is_linux && !info->secure_boot) {
|
||||
boot_el = arm_feature(env, ARM_FEATURE_EL2) ? 2 : 1;
|
||||
}
|
||||
|
||||
if ((info->psci_conduit == QEMU_PSCI_CONDUIT_HVC && boot_el >= 2) ||
|
||||
(info->psci_conduit == QEMU_PSCI_CONDUIT_SMC && boot_el == 3)) {
|
||||
info->psci_conduit = QEMU_PSCI_CONDUIT_DISABLED;
|
||||
}
|
||||
|
||||
if (info->psci_conduit != QEMU_PSCI_CONDUIT_DISABLED) {
|
||||
for (cs = first_cpu; cs; cs = CPU_NEXT(cs)) {
|
||||
Object *cpuobj = OBJECT(cs);
|
||||
|
||||
object_property_set_int(cpuobj, "psci-conduit", info->psci_conduit,
|
||||
&error_abort);
|
||||
/*
|
||||
* Secondary CPUs start in PSCI powered-down state. Like the
|
||||
* code in do_cpu_reset(), we assume first_cpu is the primary
|
||||
* CPU.
|
||||
*/
|
||||
if (cs != first_cpu) {
|
||||
object_property_set_bool(cpuobj, "start-powered-off", true,
|
||||
&error_abort);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (info->psci_conduit == QEMU_PSCI_CONDUIT_DISABLED &&
|
||||
info->is_linux && nb_cpus > 1) {
|
||||
/*
|
||||
* We're booting Linux but not using PSCI, so for SMP we need
|
||||
* to write a custom secondary CPU boot loader stub, and arrange
|
||||
* for the secondary CPU reset to make the accompanying initialization.
|
||||
*/
|
||||
if (!info->secondary_cpu_reset_hook) {
|
||||
info->secondary_cpu_reset_hook = default_reset_secondary;
|
||||
}
|
||||
if (!info->write_secondary_boot) {
|
||||
info->write_secondary_boot = default_write_secondary;
|
||||
}
|
||||
info->write_secondary_boot(cpu, info);
|
||||
} else {
|
||||
/*
|
||||
* No secondary boot stub; don't use the reset hook that would
|
||||
* have set the CPU up to call it
|
||||
*/
|
||||
info->write_secondary_boot = NULL;
|
||||
info->secondary_cpu_reset_hook = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* arm_load_dtb() may add a PSCI node so it must be called after we have
|
||||
* decided whether to enable PSCI and set the psci-conduit CPU properties.
|
||||
*/
|
||||
if (!info->skip_dtb_autoload && have_dtb(info)) {
|
||||
if (arm_load_dtb(info->dtb_start, info, info->dtb_limit, as, ms) < 0) {
|
||||
exit(1);
|
||||
|
@ -67,7 +67,6 @@ static unsigned long exynos4_board_ram_size[EXYNOS4_NUM_OF_BOARDS] = {
|
||||
static struct arm_boot_info exynos4_board_binfo = {
|
||||
.loader_start = EXYNOS4210_BASE_BOOT_ADDR,
|
||||
.smp_loader_start = EXYNOS4210_SMP_BOOT_ADDR,
|
||||
.nb_cpus = EXYNOS4210_NCPUS,
|
||||
.write_secondary_boot = exynos4210_write_secondary,
|
||||
};
|
||||
|
||||
|
@ -166,8 +166,6 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
object_property_set_int(OBJECT(&s->cpu), "psci-conduit",
|
||||
QEMU_PSCI_CONDUIT_SMC, &error_abort);
|
||||
qdev_realize(DEVICE(&s->cpu), NULL, &error_abort);
|
||||
|
||||
/*
|
||||
|
@ -159,9 +159,6 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
|
||||
for (i = 0; i < smp_cpus; i++) {
|
||||
o = OBJECT(&s->cpu[i]);
|
||||
|
||||
object_property_set_int(o, "psci-conduit", QEMU_PSCI_CONDUIT_SMC,
|
||||
&error_abort);
|
||||
|
||||
/* On uniprocessor, the CBAR is set to 0 */
|
||||
if (smp_cpus > 1) {
|
||||
object_property_set_int(o, "reset-cbar", FSL_IMX7_A7MPCORE_ADDR,
|
||||
@ -169,7 +166,10 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
|
||||
if (i) {
|
||||
/* Secondary CPUs start in PSCI powered-down state */
|
||||
/*
|
||||
* Secondary CPUs start in powered-down state (and can be
|
||||
* powered up via the SRC system reset controller)
|
||||
*/
|
||||
object_property_set_bool(o, "start-powered-off", true,
|
||||
&error_abort);
|
||||
}
|
||||
|
@ -48,66 +48,6 @@
|
||||
|
||||
/* Board init. */
|
||||
|
||||
static void hb_write_board_setup(ARMCPU *cpu,
|
||||
const struct arm_boot_info *info)
|
||||
{
|
||||
arm_write_secure_board_setup_dummy_smc(cpu, info, MVBAR_ADDR);
|
||||
}
|
||||
|
||||
static void hb_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
|
||||
{
|
||||
int n;
|
||||
uint32_t smpboot[] = {
|
||||
0xee100fb0, /* mrc p15, 0, r0, c0, c0, 5 - read current core id */
|
||||
0xe210000f, /* ands r0, r0, #0x0f */
|
||||
0xe3a03040, /* mov r3, #0x40 - jump address is 0x40 + 0x10 * core id */
|
||||
0xe0830200, /* add r0, r3, r0, lsl #4 */
|
||||
0xe59f2024, /* ldr r2, privbase */
|
||||
0xe3a01001, /* mov r1, #1 */
|
||||
0xe5821100, /* str r1, [r2, #256] - set GICC_CTLR.Enable */
|
||||
0xe3a010ff, /* mov r1, #0xff */
|
||||
0xe5821104, /* str r1, [r2, #260] - set GICC_PMR.Priority to 0xff */
|
||||
0xf57ff04f, /* dsb */
|
||||
0xe320f003, /* wfi */
|
||||
0xe5901000, /* ldr r1, [r0] */
|
||||
0xe1110001, /* tst r1, r1 */
|
||||
0x0afffffb, /* beq <wfi> */
|
||||
0xe12fff11, /* bx r1 */
|
||||
MPCORE_PERIPHBASE /* privbase: MPCore peripheral base address. */
|
||||
};
|
||||
for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
|
||||
smpboot[n] = tswap32(smpboot[n]);
|
||||
}
|
||||
rom_add_blob_fixed_as("smpboot", smpboot, sizeof(smpboot), SMP_BOOT_ADDR,
|
||||
arm_boot_address_space(cpu, info));
|
||||
}
|
||||
|
||||
static void hb_reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
|
||||
{
|
||||
CPUARMState *env = &cpu->env;
|
||||
|
||||
switch (info->nb_cpus) {
|
||||
case 4:
|
||||
address_space_stl_notdirty(&address_space_memory,
|
||||
SMP_BOOT_REG + 0x30, 0,
|
||||
MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
/* fallthrough */
|
||||
case 3:
|
||||
address_space_stl_notdirty(&address_space_memory,
|
||||
SMP_BOOT_REG + 0x20, 0,
|
||||
MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
/* fallthrough */
|
||||
case 2:
|
||||
address_space_stl_notdirty(&address_space_memory,
|
||||
SMP_BOOT_REG + 0x10, 0,
|
||||
MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
env->regs[15] = SMP_BOOT_ADDR;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#define NUM_REGS 0x200
|
||||
static void hb_regs_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
@ -271,12 +211,6 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
|
||||
object_property_set_int(cpuobj, "psci-conduit", QEMU_PSCI_CONDUIT_SMC,
|
||||
&error_abort);
|
||||
|
||||
if (n) {
|
||||
/* Secondary CPUs start in PSCI powered-down state */
|
||||
object_property_set_bool(cpuobj, "start-powered-off", true,
|
||||
&error_abort);
|
||||
}
|
||||
|
||||
if (object_property_find(cpuobj, "reset-cbar")) {
|
||||
object_property_set_int(cpuobj, "reset-cbar", MPCORE_PERIPHBASE,
|
||||
&error_abort);
|
||||
@ -390,13 +324,9 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
|
||||
* clear that the value is meaningless.
|
||||
*/
|
||||
highbank_binfo.board_id = -1;
|
||||
highbank_binfo.nb_cpus = smp_cpus;
|
||||
highbank_binfo.loader_start = 0;
|
||||
highbank_binfo.write_secondary_boot = hb_write_secondary;
|
||||
highbank_binfo.secondary_cpu_reset_hook = hb_reset_secondary;
|
||||
highbank_binfo.board_setup_addr = BOARD_SETUP_ADDR;
|
||||
highbank_binfo.write_board_setup = hb_write_board_setup;
|
||||
highbank_binfo.secure_board_setup = true;
|
||||
highbank_binfo.psci_conduit = QEMU_PSCI_CONDUIT_SMC;
|
||||
|
||||
arm_load_kernel(ARM_CPU(first_cpu), machine, &highbank_binfo);
|
||||
}
|
||||
|
@ -114,8 +114,7 @@ static void imx25_pdk_init(MachineState *machine)
|
||||
|
||||
imx25_pdk_binfo.ram_size = machine->ram_size;
|
||||
imx25_pdk_binfo.loader_start = FSL_IMX25_SDRAM0_ADDR;
|
||||
imx25_pdk_binfo.board_id = 1771,
|
||||
imx25_pdk_binfo.nb_cpus = 1;
|
||||
imx25_pdk_binfo.board_id = 1771;
|
||||
|
||||
for (i = 0; i < FSL_IMX25_NUM_ESDHCS; i++) {
|
||||
BusState *bus;
|
||||
|
@ -124,7 +124,6 @@ static void kzm_init(MachineState *machine)
|
||||
}
|
||||
|
||||
kzm_binfo.ram_size = machine->ram_size;
|
||||
kzm_binfo.nb_cpus = 1;
|
||||
|
||||
if (!qtest_enabled()) {
|
||||
arm_load_kernel(&s->soc.cpu, machine, &kzm_binfo);
|
||||
|
@ -34,7 +34,7 @@ static void mcimx6ul_evk_init(MachineState *machine)
|
||||
.loader_start = FSL_IMX6UL_MMDC_ADDR,
|
||||
.board_id = -1,
|
||||
.ram_size = machine->ram_size,
|
||||
.nb_cpus = machine->smp.cpus,
|
||||
.psci_conduit = QEMU_PSCI_CONDUIT_SMC,
|
||||
};
|
||||
|
||||
s = FSL_IMX6UL(object_new(TYPE_FSL_IMX6UL));
|
||||
|
@ -36,7 +36,7 @@ static void mcimx7d_sabre_init(MachineState *machine)
|
||||
.loader_start = FSL_IMX7_MMDC_ADDR,
|
||||
.board_id = -1,
|
||||
.ram_size = machine->ram_size,
|
||||
.nb_cpus = machine->smp.cpus,
|
||||
.psci_conduit = QEMU_PSCI_CONDUIT_SMC,
|
||||
};
|
||||
|
||||
s = FSL_IMX7(object_new(TYPE_FSL_IMX7));
|
||||
|
@ -355,10 +355,7 @@ static struct arm_boot_info npcm7xx_binfo = {
|
||||
|
||||
void npcm7xx_load_kernel(MachineState *machine, NPCM7xxState *soc)
|
||||
{
|
||||
NPCM7xxClass *sc = NPCM7XX_GET_CLASS(soc);
|
||||
|
||||
npcm7xx_binfo.ram_size = machine->ram_size;
|
||||
npcm7xx_binfo.nb_cpus = sc->num_cpus;
|
||||
|
||||
arm_load_kernel(&soc->cpu[0], machine, &npcm7xx_binfo);
|
||||
}
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu-common.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/hw.h"
|
||||
@ -35,6 +34,7 @@
|
||||
#include "sysemu/qtest.h"
|
||||
#include "sysemu/reset.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "sysemu/rtc.h"
|
||||
#include "qemu/range.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "qemu/cutils.h"
|
||||
|
@ -25,9 +25,7 @@
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/arm/allwinner-h3.h"
|
||||
|
||||
static struct arm_boot_info orangepi_binfo = {
|
||||
.nb_cpus = AW_H3_NUM_CPUS,
|
||||
};
|
||||
static struct arm_boot_info orangepi_binfo;
|
||||
|
||||
static void orangepi_init(MachineState *machine)
|
||||
{
|
||||
@ -105,6 +103,7 @@ static void orangepi_init(MachineState *machine)
|
||||
}
|
||||
orangepi_binfo.loader_start = h3->memmap[AW_H3_DEV_SDRAM];
|
||||
orangepi_binfo.ram_size = machine->ram_size;
|
||||
orangepi_binfo.psci_conduit = QEMU_PSCI_CONDUIT_SMC;
|
||||
arm_load_kernel(ARM_CPU(first_cpu), machine, &orangepi_binfo);
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,6 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qapi/error.h"
|
||||
@ -27,6 +26,7 @@
|
||||
#include "chardev/char-fe.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/qtest.h"
|
||||
#include "sysemu/rtc.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qom/object.h"
|
||||
|
@ -204,7 +204,6 @@ static void setup_boot(MachineState *machine, RaspiProcessorId processor_id,
|
||||
|
||||
s->binfo.board_id = MACH_TYPE_BCM2708;
|
||||
s->binfo.ram_size = ram_size;
|
||||
s->binfo.nb_cpus = machine->smp.cpus;
|
||||
|
||||
if (processor_id <= PROCESSOR_ID_BCM2836) {
|
||||
/*
|
||||
|
@ -363,7 +363,6 @@ static void realview_init(MachineState *machine,
|
||||
memory_region_add_subregion(sysmem, SMP_BOOT_ADDR, ram_hack);
|
||||
|
||||
realview_binfo.ram_size = ram_size;
|
||||
realview_binfo.nb_cpus = smp_cpus;
|
||||
realview_binfo.board_id = realview_board_id[board_type];
|
||||
realview_binfo.loader_start = (board_type == BOARD_PB_A8 ? 0x70000000 : 0);
|
||||
arm_load_kernel(ARM_CPU(first_cpu), machine, &realview_binfo);
|
||||
|
@ -93,7 +93,6 @@ static void sabrelite_init(MachineState *machine)
|
||||
}
|
||||
|
||||
sabrelite_binfo.ram_size = machine->ram_size;
|
||||
sabrelite_binfo.nb_cpus = machine->smp.cpus;
|
||||
sabrelite_binfo.secure_boot = true;
|
||||
sabrelite_binfo.write_secondary_boot = sabrelite_write_secondary;
|
||||
sabrelite_binfo.secondary_cpu_reset_hook = sabrelite_reset_secondary;
|
||||
|
@ -776,7 +776,6 @@ static void sbsa_ref_init(MachineState *machine)
|
||||
create_secure_ec(secure_sysmem);
|
||||
|
||||
sms->bootinfo.ram_size = machine->ram_size;
|
||||
sms->bootinfo.nb_cpus = smp_cpus;
|
||||
sms->bootinfo.board_id = -1;
|
||||
sms->bootinfo.loader_start = sbsa_ref_memmap[SBSA_MEM].base;
|
||||
sms->bootinfo.get_dtb = sbsa_ref_dtb;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user