* s390x instruction emulation fixes and corresponding TCG tests

* Extend the readconfig qtest
 * Introduce "-run-with chroot=..." and deprecate the old "-chroot" option
 * Speed up migration tests
 * Fix coding style in the coding style document
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCAAvFiEEJ7iIR+7gJQEY8+q5LtnXdP5wLbUFAmSsCYQRHHRodXRoQHJl
 ZGhhdC5jb20ACgkQLtnXdP5wLbUhLw/+Mg74FGODwb/kdPSSY+ahEmutRaQG5z74
 zWnHFYTB0xLRxu5gwV09wcFt88RjkkdsKORtp1LBRahVaKYzYSq3PxMYsDii2pdr
 Ma58RLZC/42shrzZmXEyl3ilxCCHjq2UCezX+4ca/zuTl/83znVN6Mrq28GUmp7v
 8yI78mPpZXEkLEN3cnnK3v7AsLwz439aHd3ADZ1IWUohGHQdDAj4nn5Yxp4SeIUj
 sOmCcEfLj3emNM/TTL2suohuZNwYjyLQ5iqQJ/B7v/S88PbWQUA9Cq/KpEGBLk/D
 fxDjbQ7+zpTTSQ+XihShtGdEnl4uPPixvJX43vriYDBQFsHKS7Y38cSAFVTDrQvh
 4fELCAPg8wXeoyMu7WZWINDA6dVdInCdmljHYpK+mQg7AtHu/CliPWzVUZyeW3XD
 lwybNCoyJQcA4KPAyYrkau74JrLRGtLJJQ5XtQEDsK791xjeHt1hr42QY4YeHyjM
 Utf6inp4D7RZ3O9p5EeKNVpFin5AE+RTvNZKLJicFRb0hFziUkCK61nRwS5gmvXA
 I41av1L+mLI7jvu0M2ID1CfIhFf+/w4GKNkUlcutux7uz5mzxIj0oifsONEZGNo+
 NlVKKNxfQv2eRl+9sZPWNl8q11K3bvZbpvXZS5oSLIererWIIROaxcgzxpU+EGLT
 8HhF7RZdO8w=
 =LLmM
 -----END PGP SIGNATURE-----

Merge tag 'pull-request-2023-07-10v2' of https://gitlab.com/thuth/qemu into staging

* s390x instruction emulation fixes and corresponding TCG tests
* Extend the readconfig qtest
* Introduce "-run-with chroot=..." and deprecate the old "-chroot" option
* Speed up migration tests
* Fix coding style in the coding style document

# -----BEGIN PGP SIGNATURE-----
#
# iQJFBAABCAAvFiEEJ7iIR+7gJQEY8+q5LtnXdP5wLbUFAmSsCYQRHHRodXRoQHJl
# ZGhhdC5jb20ACgkQLtnXdP5wLbUhLw/+Mg74FGODwb/kdPSSY+ahEmutRaQG5z74
# zWnHFYTB0xLRxu5gwV09wcFt88RjkkdsKORtp1LBRahVaKYzYSq3PxMYsDii2pdr
# Ma58RLZC/42shrzZmXEyl3ilxCCHjq2UCezX+4ca/zuTl/83znVN6Mrq28GUmp7v
# 8yI78mPpZXEkLEN3cnnK3v7AsLwz439aHd3ADZ1IWUohGHQdDAj4nn5Yxp4SeIUj
# sOmCcEfLj3emNM/TTL2suohuZNwYjyLQ5iqQJ/B7v/S88PbWQUA9Cq/KpEGBLk/D
# fxDjbQ7+zpTTSQ+XihShtGdEnl4uPPixvJX43vriYDBQFsHKS7Y38cSAFVTDrQvh
# 4fELCAPg8wXeoyMu7WZWINDA6dVdInCdmljHYpK+mQg7AtHu/CliPWzVUZyeW3XD
# lwybNCoyJQcA4KPAyYrkau74JrLRGtLJJQ5XtQEDsK791xjeHt1hr42QY4YeHyjM
# Utf6inp4D7RZ3O9p5EeKNVpFin5AE+RTvNZKLJicFRb0hFziUkCK61nRwS5gmvXA
# I41av1L+mLI7jvu0M2ID1CfIhFf+/w4GKNkUlcutux7uz5mzxIj0oifsONEZGNo+
# NlVKKNxfQv2eRl+9sZPWNl8q11K3bvZbpvXZS5oSLIererWIIROaxcgzxpU+EGLT
# 8HhF7RZdO8w=
# =LLmM
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 10 Jul 2023 02:37:08 PM BST
# gpg:                using RSA key 27B88847EEE0250118F3EAB92ED9D774FE702DB5
# gpg:                issuer "thuth@redhat.com"
# gpg: Good signature from "Thomas Huth <th.huth@gmx.de>" [undefined]
# gpg:                 aka "Thomas Huth <thuth@redhat.com>" [undefined]
# gpg:                 aka "Thomas Huth <th.huth@posteo.de>" [unknown]
# gpg:                 aka "Thomas Huth <huth@tuxfamily.org>" [undefined]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 27B8 8847 EEE0 2501 18F3  EAB9 2ED9 D774 FE70 2DB5

* tag 'pull-request-2023-07-10v2' of https://gitlab.com/thuth/qemu: (21 commits)
  docs/devel: Fix coding style in style.rst
  tests/qtest: massively speed up migration-test
  tests/tcg/s390x: Fix test-svc with clang
  meson.build: Skip C++ detection unless we're targeting Windows
  os-posix: Allow 'chroot' via '-run-with' and deprecate the old '-chroot' option
  tests/qtest/readconfig: Test the docs/config/q35-*.cfg files
  tests/qtest: Move mkimg() and have_qemu_img() from libqos to libqtest
  tests/qtest/readconfig-test: Allow testing for arbitrary memory sizes
  tests/tcg/s390x: Test MVCRL with a large value in R0
  tests/tcg/s390x: Test MDEB and MDEBR
  tests/tcg/s390x: Test LRA
  tests/tcg/s390x: Test LARL with a large offset
  tests/tcg/s390x: Test EPSW
  target/s390x: Fix relative long instructions with large offsets
  target/s390x: Fix LRA when DAT is off
  target/s390x: Fix LRA overwriting the top 32 bits on DAT error
  target/s390x: Fix MVCRL with a large value in R0
  target/s390x: Fix MDEB and MDEBR
  target/s390x: Fix EPSW CC reporting
  linux-user: elfload: Add more initial s390x PSW bits
  ...

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2023-07-10 15:25:19 +01:00
commit 8d309a3a97
45 changed files with 626 additions and 141 deletions

View File

@ -452,8 +452,6 @@ S: Supported
F: target/s390x/kvm/
F: target/s390x/machine.c
F: target/s390x/sigp.c
F: hw/s390x/pv.c
F: include/hw/s390x/pv.h
F: gdb-xml/s390*.xml
T: git https://github.com/borntraeger/qemu.git s390-next
L: qemu-s390x@nongnu.org

View File

@ -116,6 +116,11 @@ Use "whpx" (on Windows) or "hvf" (on macOS) instead.
Use ``-run-with async-teardown=on`` instead.
``-chroot`` (since 8.1)
'''''''''''''''''''''''
Use ``-run-with chroot=dir`` instead.
``-singlestep`` (since 8.1)
'''''''''''''''''''''''''''

View File

@ -567,7 +567,8 @@ For example, instead of
.. code-block:: c
int somefunc(void) {
int somefunc(void)
{
int ret = -1;
char *foo = g_strdup_printf("foo%", "wibble");
GList *bar = .....
@ -588,7 +589,8 @@ Using g_autofree/g_autoptr enables the code to be written as:
.. code-block:: c
int somefunc(void) {
int somefunc(void)
{
g_autofree char *foo = g_strdup_printf("foo%", "wibble");
g_autoptr (GList) bar = .....
@ -613,7 +615,8 @@ are still some caveats to beware of
.. code-block:: c
char *somefunc(void) {
char *somefunc(void)
{
g_autofree char *foo = g_strdup_printf("foo%", "wibble");
g_autoptr (GList) bar = .....

View File

@ -26,7 +26,7 @@
#include "hw/s390x/vfio-ccw.h"
#include "hw/s390x/css.h"
#include "hw/s390x/ebcdic.h"
#include "hw/s390x/pv.h"
#include "target/s390x/kvm/pv.h"
#include "hw/scsi/scsi.h"
#include "hw/virtio/virtio-net.h"
#include "ipl.h"

View File

@ -22,7 +22,6 @@ s390x_ss.add(when: 'CONFIG_KVM', if_true: files(
'tod-kvm.c',
's390-skeys-kvm.c',
's390-stattrib-kvm.c',
'pv.c',
's390-pci-kvm.c',
))
s390x_ss.add(when: 'CONFIG_TCG', if_true: files(

View File

@ -14,7 +14,7 @@
#include <linux/kvm.h>
#include "kvm/kvm_s390x.h"
#include "hw/s390x/pv.h"
#include "target/s390x/kvm/pv.h"
#include "hw/s390x/s390-pci-bus.h"
#include "hw/s390x/s390-pci-kvm.h"
#include "hw/s390x/s390-pci-inst.h"

View File

@ -42,7 +42,7 @@
#include "hw/s390x/tod.h"
#include "sysemu/sysemu.h"
#include "sysemu/cpus.h"
#include "hw/s390x/pv.h"
#include "target/s390x/kvm/pv.h"
#include "migration/blocker.h"
#include "qapi/visitor.h"

View File

@ -13,7 +13,7 @@
#include "qemu/module.h"
#include "sysemu/runstate.h"
#include "hw/s390x/tod.h"
#include "hw/s390x/pv.h"
#include "target/s390x/kvm/pv.h"
#include "kvm/kvm_s390x.h"
static void kvm_s390_get_tod_raw(S390TOD *tod, Error **errp)

View File

@ -1635,7 +1635,9 @@ const char *elf_hwcap_str(uint32_t bit)
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
{
regs->psw.addr = infop->entry;
regs->psw.mask = PSW_MASK_64 | PSW_MASK_32;
regs->psw.mask = PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | \
PSW_MASK_MCHECK | PSW_MASK_PSTATE | PSW_MASK_64 | \
PSW_MASK_32;
regs->gprs[15] = infop->start_stack;
}

View File

@ -20,7 +20,7 @@ config_host = keyval.load(meson.current_build_dir() / 'config-host.mak')
cc = meson.get_compiler('c')
all_languages = ['c']
if add_languages('cpp', required: false, native: false)
if targetos == 'windows' and add_languages('cpp', required: false, native: false)
all_languages += ['cpp']
cxx = meson.get_compiler('cpp')
endif

View File

@ -38,6 +38,7 @@
#include "qemu/cutils.h"
#include "qemu/config-file.h"
#include "qemu/option.h"
#include "qemu/module.h"
#ifdef CONFIG_LINUX
#include <sys/prctl.h>
@ -148,6 +149,7 @@ int os_parse_cmd_args(int index, const char *optarg)
}
break;
case QEMU_OPTION_chroot:
warn_report("option is deprecated, use '-run-with chroot=...' instead");
chroot_dir = optarg;
break;
case QEMU_OPTION_daemonize:
@ -158,18 +160,25 @@ int os_parse_cmd_args(int index, const char *optarg)
case QEMU_OPTION_asyncteardown:
init_async_teardown();
break;
#endif
case QEMU_OPTION_run_with: {
const char *str;
QemuOpts *opts = qemu_opts_parse_noisily(qemu_find_opts("run-with"),
optarg, false);
if (!opts) {
exit(1);
}
#if defined(CONFIG_LINUX)
if (qemu_opt_get_bool(opts, "async-teardown", false)) {
init_async_teardown();
}
#endif
str = qemu_opt_get(opts, "chroot");
if (str) {
chroot_dir = str;
}
break;
}
#endif
default:
return -1;
}
@ -348,3 +357,27 @@ int os_mlock(void)
return -ENOSYS;
#endif
}
static QemuOptsList qemu_run_with_opts = {
.name = "run-with",
.head = QTAILQ_HEAD_INITIALIZER(qemu_run_with_opts.head),
.desc = {
#if defined(CONFIG_LINUX)
{
.name = "async-teardown",
.type = QEMU_OPT_BOOL,
},
#endif
{
.name = "chroot",
.type = QEMU_OPT_STRING,
},
{ /* end of list */ }
},
};
static void register_runwith(void)
{
qemu_add_opts(&qemu_run_with_opts);
}
opts_init(register_runwith);

View File

@ -4677,11 +4677,12 @@ ERST
#ifndef _WIN32
DEF("chroot", HAS_ARG, QEMU_OPTION_chroot, \
"-chroot dir chroot to dir just before starting the VM\n",
"-chroot dir chroot to dir just before starting the VM (deprecated)\n",
QEMU_ARCH_ALL)
#endif
SRST
``-chroot dir``
Deprecated, use '-run-with chroot=...' instead.
Immediately before starting guest execution, chroot to the specified
directory. Especially useful in combination with -runas.
ERST
@ -4868,13 +4869,16 @@ SRST
This option is deprecated and should no longer be used. The new option
``-run-with async-teardown=on`` is a replacement.
ERST
#endif
#ifdef CONFIG_POSIX
DEF("run-with", HAS_ARG, QEMU_OPTION_run_with,
"-run-with async-teardown[=on|off]\n"
" misc QEMU process lifecycle options\n"
" async-teardown=on enables asynchronous teardown\n",
"-run-with [async-teardown=on|off][,chroot=dir]\n"
" Set miscellaneous QEMU process lifecycle options:\n"
" async-teardown=on enables asynchronous teardown (Linux only)\n"
" chroot=dir chroot to dir just before starting the VM\n",
QEMU_ARCH_ALL)
SRST
``-run-with``
``-run-with [async-teardown=on|off][,chroot=dir]``
Set QEMU process lifecycle options.
``async-teardown=on`` enables asynchronous teardown. A new process called
@ -4887,6 +4891,10 @@ SRST
performed correctly. This only works if the cleanup process is not
forcefully killed with SIGKILL before the main QEMU process has
terminated completely.
``chroot=dir`` can be used for doing a chroot to the specified directory
immediately before starting the guest execution. This is especially useful
in combination with -runas.
ERST
#endif

View File

@ -17,8 +17,8 @@
#include "s390x-internal.h"
#include "elf.h"
#include "sysemu/dump.h"
#include "hw/s390x/pv.h"
#include "kvm/kvm_s390x.h"
#include "target/s390x/kvm/pv.h"
struct S390xUserRegsStruct {
uint64_t psw[2];

View File

@ -33,7 +33,7 @@
#include "qapi/qapi-visit-run-state.h"
#include "sysemu/hw_accel.h"
#include "hw/s390x/pv.h"
#include "target/s390x/kvm/pv.h"
#include "hw/boards.h"
#include "sysemu/sysemu.h"
#include "sysemu/tcg.h"

View File

@ -15,7 +15,7 @@
#include "qemu/module.h"
#include "cpu_features.h"
#ifndef CONFIG_USER_ONLY
#include "hw/s390x/pv.h"
#include "target/s390x/kvm/pv.h"
#endif
#define DEF_FEAT(_FEAT, _NAME, _TYPE, _BIT, _DESC) \

View File

@ -24,7 +24,7 @@
#include "qemu/qemu-print.h"
#ifndef CONFIG_USER_ONLY
#include "sysemu/sysemu.h"
#include "hw/s390x/pv.h"
#include "target/s390x/kvm/pv.h"
#endif
#define CPUDEF_INIT(_type, _gen, _ec_ga, _mha_pow, _hmfai, _name, _desc) \

View File

@ -19,9 +19,9 @@
#include "sysemu/cpus.h"
#include "hw/s390x/ipl.h"
#include "hw/s390x/s390-virtio-ccw.h"
#include "hw/s390x/pv.h"
#include "sysemu/kvm.h"
#include "kvm/kvm_s390x.h"
#include "target/s390x/kvm/pv.h"
#include "qemu/error-report.h"

View File

@ -24,7 +24,7 @@
#include "gdbstub/helpers.h"
#include "qemu/timer.h"
#include "hw/s390x/ioinst.h"
#include "hw/s390x/pv.h"
#include "target/s390x/kvm/pv.h"
#include "sysemu/hw_accel.h"
#include "sysemu/runstate.h"

View File

@ -355,7 +355,7 @@ DEF_HELPER_FLAGS_4(idte, TCG_CALL_NO_RWG, void, env, i64, i64, i32)
DEF_HELPER_FLAGS_4(ipte, TCG_CALL_NO_RWG, void, env, i64, i64, i32)
DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_NO_RWG, void, env)
DEF_HELPER_FLAGS_1(purge, TCG_CALL_NO_RWG, void, env)
DEF_HELPER_2(lra, i64, env, i64)
DEF_HELPER_3(lra, i64, env, i64, i64)
DEF_HELPER_1(per_check_exception, void, env)
DEF_HELPER_FLAGS_3(per_branch, TCG_CALL_NO_RWG, void, env, i64, i64)
DEF_HELPER_FLAGS_2(per_ifetch, TCG_CALL_NO_RWG, void, env, i64)

View File

@ -16,7 +16,7 @@
#include "hw/s390x/ioinst.h"
#include "trace.h"
#include "hw/s390x/s390-pci-bus.h"
#include "hw/s390x/pv.h"
#include "target/s390x/kvm/pv.h"
/* All I/O instructions but chsc use the s format */
static uint64_t get_address_from_regs(CPUS390XState *env, uint32_t ipb,

View File

@ -50,7 +50,7 @@
#include "exec/memattrs.h"
#include "hw/s390x/s390-virtio-ccw.h"
#include "hw/s390x/s390-virtio-hcall.h"
#include "hw/s390x/pv.h"
#include "target/s390x/kvm/pv.h"
#ifndef DEBUG_KVM
#define DEBUG_KVM 0

View File

@ -1,5 +1,6 @@
s390x_ss.add(when: 'CONFIG_KVM', if_true: files(
'pv.c',
'kvm.c'
), if_false: files(
'stubs.c'

View File

@ -21,9 +21,9 @@
#include "qom/object_interfaces.h"
#include "exec/confidential-guest-support.h"
#include "hw/s390x/ipl.h"
#include "hw/s390x/pv.h"
#include "hw/s390x/sclp.h"
#include "target/s390x/kvm/kvm_s390x.h"
#include "target/s390x/kvm/pv.h"
static bool info_valid;
static struct kvm_s390_pv_info_vm info_vm;

View File

@ -417,7 +417,7 @@ int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
vaddr &= TARGET_PAGE_MASK;
if (!(env->psw.mask & PSW_MASK_DAT)) {
if (rw != MMU_S390_LRA && !(env->psw.mask & PSW_MASK_DAT)) {
*raddr = vaddr;
goto nodat;
}

View File

@ -306,8 +306,9 @@ uint64_t HELPER(mdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
/* 64/32-bit FP multiplication */
uint64_t HELPER(mdeb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
{
float64 f1_64 = float32_to_float64(f1, &env->fpu_status);
float64 ret = float32_to_float64(f2, &env->fpu_status);
ret = float64_mul(f1, ret, &env->fpu_status);
ret = float64_mul(f1_64, ret, &env->fpu_status);
handle_exceptions(env, false, GETPC());
return ret;
}

View File

@ -667,11 +667,11 @@
F(0xb317, MEEBR, RRE, Z, e1, e2, new, e1, meeb, 0, IF_BFP)
F(0xb31c, MDBR, RRE, Z, f1, f2, new, f1, mdb, 0, IF_BFP)
F(0xb34c, MXBR, RRE, Z, x1, x2, new_x, x1, mxb, 0, IF_BFP)
F(0xb30c, MDEBR, RRE, Z, f1, e2, new, f1, mdeb, 0, IF_BFP)
F(0xb30c, MDEBR, RRE, Z, e1, e2, new, f1, mdeb, 0, IF_BFP)
F(0xb307, MXDBR, RRE, Z, f1, f2, new_x, x1, mxdb, 0, IF_BFP)
F(0xed17, MEEB, RXE, Z, e1, m2_32u, new, e1, meeb, 0, IF_BFP)
F(0xed1c, MDB, RXE, Z, f1, m2_64, new, f1, mdb, 0, IF_BFP)
F(0xed0c, MDEB, RXE, Z, f1, m2_32u, new, f1, mdeb, 0, IF_BFP)
F(0xed0c, MDEB, RXE, Z, e1, m2_32u, new, f1, mdeb, 0, IF_BFP)
F(0xed07, MXDB, RXE, Z, f1, m2_64, new_x, x1, mxdb, 0, IF_BFP)
/* MULTIPLY HALFWORD */
C(0x4c00, MH, RX_a, Z, r1_o, m2_16s, new, r1_32, mul, 0)

View File

@ -514,6 +514,7 @@ void HELPER(mvcrl)(CPUS390XState *env, uint64_t l, uint64_t dest, uint64_t src)
int32_t i;
/* MVCRL always copies one more byte than specified - maximum is 256 */
l &= 0xff;
l++;
access_prepare(&srca, env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
@ -2355,7 +2356,7 @@ void HELPER(purge)(CPUS390XState *env)
}
/* load real address */
uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr)
uint64_t HELPER(lra)(CPUS390XState *env, uint64_t r1, uint64_t addr)
{
uint64_t asc = env->psw.mask & PSW_MASK_ASC;
uint64_t ret, tec;
@ -2369,7 +2370,7 @@ uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr)
exc = mmu_translate(env, addr, MMU_S390_LRA, asc, &ret, &flags, &tec);
if (exc) {
cc = 3;
ret = exc | 0x80000000;
ret = (r1 & 0xFFFFFFFF00000000ULL) | exc | 0x80000000;
} else {
cc = 0;
ret |= addr & ~TARGET_PAGE_MASK;

View File

@ -2383,10 +2383,14 @@ static DisasJumpType op_epsw(DisasContext *s, DisasOps *o)
int r1 = get_field(s, r1);
int r2 = get_field(s, r2);
TCGv_i64 t = tcg_temp_new_i64();
TCGv_i64 t_cc = tcg_temp_new_i64();
/* Note the "subsequently" in the PoO, which implies a defined result
if r1 == r2. Thus we cannot defer these writes to an output hook. */
gen_op_calc_cc(s);
tcg_gen_extu_i32_i64(t_cc, cc_op);
tcg_gen_shri_i64(t, psw_mask, 32);
tcg_gen_deposit_i64(t, t, t_cc, 12, 2);
store_reg32_i64(r1, t);
if (r2 != 0) {
store_reg32_i64(r2, psw_mask);
@ -2928,7 +2932,7 @@ static DisasJumpType op_lctlg(DisasContext *s, DisasOps *o)
static DisasJumpType op_lra(DisasContext *s, DisasOps *o)
{
gen_helper_lra(o->out, cpu_env, o->in2);
gen_helper_lra(o->out, cpu_env, o->out, o->in2);
set_cc_static(s);
return DISAS_NEXT;
}
@ -5790,7 +5794,7 @@ static TCGv gen_ri2(DisasContext *s)
disas_jdest(s, i2, is_imm, imm, ri2);
if (is_imm) {
ri2 = tcg_constant_i64(s->base.pc_next + imm * 2);
ri2 = tcg_constant_i64(s->base.pc_next + (int64_t)imm * 2);
}
return ri2;

View File

@ -137,56 +137,9 @@ void migrate(QOSState *from, QOSState *to, const char *uri)
migrate_allocator(&from->alloc, &to->alloc);
}
bool have_qemu_img(void)
{
char *rpath;
const char *path = getenv("QTEST_QEMU_IMG");
if (!path) {
return false;
}
rpath = realpath(path, NULL);
if (!rpath) {
return false;
} else {
free(rpath);
return true;
}
}
void mkimg(const char *file, const char *fmt, unsigned size_mb)
{
gchar *cli;
bool ret;
int rc;
GError *err = NULL;
char *qemu_img_path;
gchar *out, *out2;
char *qemu_img_abs_path;
qemu_img_path = getenv("QTEST_QEMU_IMG");
g_assert(qemu_img_path);
qemu_img_abs_path = realpath(qemu_img_path, NULL);
g_assert(qemu_img_abs_path);
cli = g_strdup_printf("%s create -f %s %s %uM", qemu_img_abs_path,
fmt, file, size_mb);
ret = g_spawn_command_line_sync(cli, &out, &out2, &rc, &err);
if (err || !g_spawn_check_exit_status(rc, &err)) {
fprintf(stderr, "%s\n", err->message);
g_error_free(err);
}
g_assert(ret && !err);
g_free(out);
g_free(out2);
g_free(cli);
free(qemu_img_abs_path);
}
void mkqcow2(const char *file, unsigned size_mb)
{
return mkimg(file, "qcow2", size_mb);
g_assert_true(mkimg(file, "qcow2", size_mb));
}
void prepare_blkdebug_script(const char *debug_fn, const char *event)

View File

@ -27,8 +27,6 @@ QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...)
G_GNUC_PRINTF(2, 3);
void qtest_common_shutdown(QOSState *qs);
void qtest_shutdown(QOSState *qs);
bool have_qemu_img(void);
void mkimg(const char *file, const char *fmt, unsigned size_mb);
void mkqcow2(const char *file, unsigned size_mb);
void migrate(QOSState *from, QOSState *to, const char *uri);
void prepare_blkdebug_script(const char *debug_fn, const char *event);

View File

@ -1742,3 +1742,55 @@ bool qtest_qom_get_bool(QTestState *s, const char *path, const char *property)
return b;
}
bool have_qemu_img(void)
{
char *rpath;
const char *path = getenv("QTEST_QEMU_IMG");
if (!path) {
return false;
}
rpath = realpath(path, NULL);
if (!rpath) {
return false;
} else {
free(rpath);
return true;
}
}
bool mkimg(const char *file, const char *fmt, unsigned size_mb)
{
gchar *cli;
bool ret;
int rc;
GError *err = NULL;
char *qemu_img_path;
gchar *out, *out2;
char *qemu_img_abs_path;
qemu_img_path = getenv("QTEST_QEMU_IMG");
if (!qemu_img_path) {
return false;
}
qemu_img_abs_path = realpath(qemu_img_path, NULL);
if (!qemu_img_abs_path) {
return false;
}
cli = g_strdup_printf("%s create -f %s %s %uM", qemu_img_abs_path,
fmt, file, size_mb);
ret = g_spawn_command_line_sync(cli, &out, &out2, &rc, &err);
if (err || !g_spawn_check_exit_status(rc, &err)) {
fprintf(stderr, "%s\n", err->message);
g_error_free(err);
}
g_free(out);
g_free(out2);
g_free(cli);
free(qemu_img_abs_path);
return ret && !err;
}

View File

@ -994,4 +994,24 @@ bool qtest_qom_get_bool(QTestState *s, const char *path, const char *property);
*/
pid_t qtest_pid(QTestState *s);
/**
* have_qemu_img:
*
* Returns: true if "qemu-img" is available.
*/
bool have_qemu_img(void);
/**
* mkimg:
* @file: File name of the image that should be created
* @fmt: Format, e.g. "qcow2" or "raw"
* @size_mb: Size of the image in megabytes
*
* Create a disk image with qemu-img. Note that the QTEST_QEMU_IMG
* environment variable must point to the qemu-img file.
*
* Returns: true if the image has been created successfully.
*/
bool mkimg(const char *file, const char *fmt, unsigned size_mb);
#endif

View File

@ -46,6 +46,20 @@ static bool uffd_feature_thread_id;
static bool got_src_stop;
static bool got_dst_resume;
/*
* An initial 3 MB offset is used as that corresponds
* to ~1 sec of data transfer with our bandwidth setting.
*/
#define MAGIC_OFFSET_BASE (3 * 1024 * 1024)
/*
* A further 1k is added to ensure we're not a multiple
* of TEST_MEM_PAGE_SIZE, thus avoid clash with writes
* from the migration guest workload.
*/
#define MAGIC_OFFSET_SHUFFLE 1024
#define MAGIC_OFFSET (MAGIC_OFFSET_BASE + MAGIC_OFFSET_SHUFFLE)
#define MAGIC_MARKER 0xFEED12345678CAFEULL
/*
* Dirtylimit stop working if dirty page rate error
* value less than DIRTYLIMIT_TOLERANCE_RANGE
@ -445,6 +459,91 @@ static void migrate_ensure_converge(QTestState *who)
migrate_set_parameter_int(who, "downtime-limit", 30 * 1000);
}
/*
* Our goal is to ensure that we run a single full migration
* iteration, and also dirty memory, ensuring that at least
* one further iteration is required.
*
* We can't directly synchronize with the start of a migration
* so we have to apply some tricks monitoring memory that is
* transferred.
*
* Initially we set the migration bandwidth to an insanely
* low value, with tiny max downtime too. This basically
* guarantees migration will never complete.
*
* This will result in a test that is unacceptably slow though,
* so we can't let the entire migration pass run at this speed.
* Our intent is to let it run just long enough that we can
* prove data prior to the marker has been transferred *AND*
* also prove this transferred data is dirty again.
*
* Before migration starts, we write a 64-bit magic marker
* into a fixed location in the src VM RAM.
*
* Then watch dst memory until the marker appears. This is
* proof that start_address -> MAGIC_OFFSET_BASE has been
* transferred.
*
* Finally we go back to the source and read a byte just
* before the marker untill we see it flip in value. This
* is proof that start_address -> MAGIC_OFFSET_BASE
* is now dirty again.
*
* IOW, we're guaranteed at least a 2nd migration pass
* at this point.
*
* We can now let migration run at full speed to finish
* the test
*/
static void migrate_prepare_for_dirty_mem(QTestState *from)
{
/*
* The guest workflow iterates from start_address to
* end_address, writing 1 byte every TEST_MEM_PAGE_SIZE
* bytes.
*
* IOW, if we write to mem at a point which is NOT
* a multiple of TEST_MEM_PAGE_SIZE, our write won't
* conflict with the migration workflow.
*
* We put in a marker here, that we'll use to determine
* when the data has been transferred to the dst.
*/
qtest_writeq(from, start_address + MAGIC_OFFSET, MAGIC_MARKER);
}
static void migrate_wait_for_dirty_mem(QTestState *from,
QTestState *to)
{
uint64_t watch_address = start_address + MAGIC_OFFSET_BASE;
uint64_t marker_address = start_address + MAGIC_OFFSET;
uint8_t watch_byte;
/*
* Wait for the MAGIC_MARKER to get transferred, as an
* indicator that a migration pass has made some known
* amount of progress.
*/
do {
usleep(1000 * 10);
} while (qtest_readq(to, marker_address) != MAGIC_MARKER);
/*
* Now ensure that already transferred bytes are
* dirty again from the guest workload. Note the
* guest byte value will wrap around and by chance
* match the original watch_byte. This is harmless
* as we'll eventually see a different value if we
* keep watching
*/
watch_byte = qtest_readb(from, watch_address);
do {
usleep(1000 * 10);
} while (qtest_readb(from, watch_address) == watch_byte);
}
static void migrate_pause(QTestState *who)
{
qtest_qmp_assert_success(who, "{ 'execute': 'migrate-pause' }");
@ -577,7 +676,10 @@ typedef struct {
MIG_TEST_FAIL_DEST_QUIT_ERR,
} result;
/* Optional: set number of migration passes to wait for, if live==true */
/*
* Optional: set number of migration passes to wait for, if live==true.
* If zero, then merely wait for a few MB of dirty data
*/
unsigned int iterations;
/*
@ -1165,12 +1267,14 @@ static int migrate_postcopy_prepare(QTestState **from_ptr,
migrate_ensure_non_converge(from);
migrate_prepare_for_dirty_mem(from);
/* Wait for the first serial output from the source */
wait_for_serial("src_serial");
migrate_qmp(from, uri, "{}");
wait_for_migration_pass(from);
migrate_wait_for_dirty_mem(from, to);
*from_ptr = from;
*to_ptr = to;
@ -1405,14 +1509,8 @@ static void test_precopy_common(MigrateCommon *args)
}
if (args->live) {
/*
* Testing live migration, we want to ensure that some
* memory is re-dirtied after being transferred, so that
* we exercise logic for dirty page handling. We achieve
* this with a ridiculosly low bandwidth that guarantees
* non-convergance.
*/
migrate_ensure_non_converge(from);
migrate_prepare_for_dirty_mem(from);
} else {
/*
* Testing non-live migration, we allow it to run at
@ -1447,13 +1545,16 @@ static void test_precopy_common(MigrateCommon *args)
}
} else {
if (args->live) {
if (args->iterations) {
while (args->iterations--) {
wait_for_migration_pass(from);
}
} else {
/*
* For initial iteration(s) we must do a full pass,
* but for the final iteration, we need only wait
* for some dirty mem before switching to converge
*/
while (args->iterations > 1) {
wait_for_migration_pass(from);
args->iterations--;
}
migrate_wait_for_dirty_mem(from, to);
migrate_ensure_converge(from);
@ -1586,6 +1687,9 @@ static void test_ignore_shared(void)
return;
}
migrate_ensure_non_converge(from);
migrate_prepare_for_dirty_mem(from);
migrate_set_capability(from, "x-ignore-shared", true);
migrate_set_capability(to, "x-ignore-shared", true);
@ -1594,7 +1698,7 @@ static void test_ignore_shared(void)
migrate_qmp(from, uri, "{}");
wait_for_migration_pass(from);
migrate_wait_for_dirty_mem(from, to);
if (!got_src_stop) {
qtest_qmp_eventwait(from, "STOP");
@ -2325,6 +2429,7 @@ static void test_multifd_tcp_cancel(void)
}
migrate_ensure_non_converge(from);
migrate_prepare_for_dirty_mem(from);
migrate_set_parameter_int(from, "multifd-channels", 16);
migrate_set_parameter_int(to, "multifd-channels", 16);
@ -2343,7 +2448,7 @@ static void test_multifd_tcp_cancel(void)
migrate_qmp(from, uri, "{}");
wait_for_migration_pass(from);
migrate_wait_for_dirty_mem(from, to);
migrate_cancel(from);
@ -2372,11 +2477,13 @@ static void test_multifd_tcp_cancel(void)
wait_for_migration_status(from, "cancelled", NULL);
migrate_ensure_converge(from);
migrate_ensure_non_converge(from);
migrate_qmp(from, uri, "{}");
wait_for_migration_pass(from);
migrate_wait_for_dirty_mem(from, to);
migrate_ensure_converge(from);
if (!got_src_stop) {
qtest_qmp_eventwait(from, "STOP");

View File

@ -48,7 +48,7 @@ static QTestState *qtest_init_with_config(const char *cfgdata)
return qts;
}
static void test_x86_memdev_resp(QObject *res)
static void test_x86_memdev_resp(QObject *res, const char *mem_id, int size)
{
Visitor *v;
g_autoptr(MemdevList) memdevs = NULL;
@ -63,8 +63,8 @@ static void test_x86_memdev_resp(QObject *res)
g_assert(!memdevs->next);
memdev = memdevs->value;
g_assert_cmpstr(memdev->id, ==, "ram");
g_assert_cmpint(memdev->size, ==, 200 * MiB);
g_assert_cmpstr(memdev->id, ==, mem_id);
g_assert_cmpint(memdev->size, ==, size * MiB);
visit_free(v);
}
@ -80,7 +80,7 @@ static void test_x86_memdev(void)
qts = qtest_init_with_config(cfgdata);
/* Test valid command */
resp = qtest_qmp(qts, "{ 'execute': 'query-memdev' }");
test_x86_memdev_resp(qdict_get(resp, "return"));
test_x86_memdev_resp(qdict_get(resp, "return"), "ram", 200);
qobject_unref(resp);
qtest_quit(qts);
@ -197,6 +197,189 @@ static void test_docs_config_ich9(void)
qtest_quit(qts);
}
#if defined(CONFIG_POSIX) && defined(CONFIG_SLIRP)
static char *make_temp_img(const char *template, const char *format, int size)
{
GError *error = NULL;
char *temp_name;
int fd;
/* Create a temporary image names */
fd = g_file_open_tmp(template, &temp_name, &error);
if (fd == -1) {
fprintf(stderr, "unable to create file: %s\n", error->message);
g_error_free(error);
return NULL;
}
close(fd);
if (!mkimg(temp_name, format, size)) {
fprintf(stderr, "qemu-img failed to create %s\n", temp_name);
g_free(temp_name);
return NULL;
}
return temp_name;
}
struct device {
const char *name;
const char *type;
};
static void test_docs_q35(const char *input_file, struct device *devices)
{
QTestState *qts;
QDict *resp;
QObject *qobj;
int ret, i;
g_autofree char *cfg_file = NULL, *sedcmd = NULL;
g_autofree char *hd_file = NULL, *cd_file = NULL;
/* Check that all the devices are available in the QEMU binary */
for (i = 0; devices[i].name; i++) {
if (!qtest_has_device(devices[i].type)) {
g_test_skip("one of the required devices is not available");
return;
}
}
hd_file = make_temp_img("qtest_disk_XXXXXX.qcow2", "qcow2", 1);
cd_file = make_temp_img("qtest_cdrom_XXXXXX.iso", "raw", 1);
if (!hd_file || !cd_file) {
g_test_skip("could not create disk images");
goto cleanup;
}
/* Create a temporary config file where we replace the disk image names */
ret = g_file_open_tmp("q35-emulated-XXXXXX.cfg", &cfg_file, NULL);
if (ret == -1) {
g_test_skip("could not create temporary config file");
goto cleanup;
}
close(ret);
sedcmd = g_strdup_printf("sed -e 's,guest.qcow2,%s,' -e 's,install.iso,%s,'"
" %s %s > '%s'",
hd_file, cd_file,
!qtest_has_accel("kvm") ? "-e '/accel/d'" : "",
input_file, cfg_file);
ret = system(sedcmd);
if (ret) {
g_test_skip("could not modify temporary config file");
goto cleanup;
}
qts = qtest_initf("-machine none -nodefaults -readconfig %s", cfg_file);
/* Check memory size */
resp = qtest_qmp(qts, "{ 'execute': 'query-memdev' }");
test_x86_memdev_resp(qdict_get(resp, "return"), "pc.ram", 1024);
qobject_unref(resp);
resp = qtest_qmp(qts, "{ 'execute': 'qom-list',"
" 'arguments': {'path': '/machine/peripheral' }}");
qobj = qdict_get(resp, "return");
/* Check that all the devices have been created */
for (i = 0; devices[i].name; i++) {
test_object_available(qobj, devices[i].name, devices[i].type);
}
qobject_unref(resp);
qtest_quit(qts);
cleanup:
if (hd_file) {
unlink(hd_file);
}
if (cd_file) {
unlink(cd_file);
}
if (cfg_file) {
unlink(cfg_file);
}
}
static void test_docs_q35_emulated(void)
{
struct device devices[] = {
{ "ich9-pcie-port-1", "ioh3420" },
{ "ich9-pcie-port-2", "ioh3420" },
{ "ich9-pcie-port-3", "ioh3420" },
{ "ich9-pcie-port-4", "ioh3420" },
{ "ich9-pci-bridge", "i82801b11-bridge" },
{ "ich9-ehci-1", "ich9-usb-ehci1" },
{ "ich9-ehci-2", "ich9-usb-ehci2" },
{ "ich9-uhci-1", "ich9-usb-uhci1" },
{ "ich9-uhci-2", "ich9-usb-uhci2" },
{ "ich9-uhci-3", "ich9-usb-uhci3" },
{ "ich9-uhci-4", "ich9-usb-uhci4" },
{ "ich9-uhci-5", "ich9-usb-uhci5" },
{ "ich9-uhci-6", "ich9-usb-uhci6" },
{ "sata-disk", "ide-hd" },
{ "sata-optical-disk", "ide-cd" },
{ "net", "e1000" },
{ "video", "VGA" },
{ "ich9-hda-audio", "ich9-intel-hda" },
{ "ich9-hda-duplex", "hda-duplex" },
{ NULL, NULL }
};
test_docs_q35("docs/config/q35-emulated.cfg", devices);
}
static void test_docs_q35_virtio_graphical(void)
{
struct device devices[] = {
{ "pcie.1", "pcie-root-port" },
{ "pcie.2", "pcie-root-port" },
{ "pcie.3", "pcie-root-port" },
{ "pcie.4", "pcie-root-port" },
{ "pcie.5", "pcie-root-port" },
{ "pcie.6", "pcie-root-port" },
{ "pcie.7", "pcie-root-port" },
{ "pcie.8", "pcie-root-port" },
{ "scsi", "virtio-scsi-pci" },
{ "scsi-disk", "scsi-hd" },
{ "scsi-optical-disk", "scsi-cd" },
{ "net", "virtio-net-pci" },
{ "usb", "nec-usb-xhci" },
{ "tablet", "usb-tablet" },
{ "video", "qxl-vga" },
{ "sound", "ich9-intel-hda" },
{ "duplex", "hda-duplex" },
{ NULL, NULL }
};
test_docs_q35("docs/config/q35-virtio-graphical.cfg", devices);
}
static void test_docs_q35_virtio_serial(void)
{
struct device devices[] = {
{ "pcie.1", "pcie-root-port" },
{ "pcie.2", "pcie-root-port" },
{ "pcie.3", "pcie-root-port" },
{ "pcie.4", "pcie-root-port" },
{ "pcie.5", "pcie-root-port" },
{ "pcie.6", "pcie-root-port" },
{ "pcie.7", "pcie-root-port" },
{ "pcie.8", "pcie-root-port" },
{ "scsi", "virtio-scsi-pci" },
{ "scsi-disk", "scsi-hd" },
{ "scsi-optical-disk", "scsi-cd" },
{ "net", "virtio-net-pci" },
{ NULL, NULL }
};
test_docs_q35("docs/config/q35-virtio-serial.cfg", devices);
}
#endif /* CONFIG_LINUX */
int main(int argc, char *argv[])
{
const char *arch;
@ -211,6 +394,19 @@ int main(int argc, char *argv[])
qtest_has_device("ich9-usb-uhci1")) {
qtest_add_func("readconfig/x86/ich9-ehci-uhci", test_docs_config_ich9);
}
#if defined(CONFIG_POSIX) && defined(CONFIG_SLIRP)
qtest_add_func("readconfig/x86/q35-emulated", test_docs_q35_emulated);
qtest_add_func("readconfig/x86/q35-virtio-graphical",
test_docs_q35_virtio_graphical);
if (g_test_slow()) {
/*
* q35-virtio-serial.cfg is a subset of q35-virtio-graphical.cfg,
* so we can skip the test in quick mode
*/
qtest_add_func("readconfig/x86/q35-virtio-serial",
test_docs_q35_virtio_serial);
}
#endif
}
#if defined(CONFIG_SPICE) && !defined(__FreeBSD__)
qtest_add_func("readconfig/spice", test_spice);

View File

@ -20,6 +20,7 @@ ASM_TESTS = \
sam \
lpsw \
lpswe-early \
lra \
ssm-early \
stosm-early \
unaligned-lowcore

View File

@ -36,6 +36,9 @@ TESTS+=rxsbg
TESTS+=ex-relative-long
TESTS+=ex-branch
TESTS+=mxdb
TESTS+=epsw
TESTS+=larl
TESTS+=mdeb
cdsg: CFLAGS+=-pthread
cdsg: LDFLAGS+=-pthread

23
tests/tcg/s390x/epsw.c Normal file
View File

@ -0,0 +1,23 @@
/*
* Test the EPSW instruction.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <assert.h>
#include <stdlib.h>
int main(void)
{
unsigned long r1 = 0x1234567887654321UL, r2 = 0x8765432112345678UL;
asm("cr %[r1],%[r2]\n" /* cc = 1 */
"epsw %[r1],%[r2]"
: [r1] "+r" (r1), [r2] "+r" (r2) : : "cc");
/* Do not check the R and RI bits. */
r1 &= ~0x40000008UL;
assert(r1 == 0x1234567807051001UL);
assert(r2 == 0x8765432180000000UL);
return EXIT_SUCCESS;
}

View File

@ -25,7 +25,7 @@ def run_test():
gdb.execute("si")
report("larl\t" in gdb.execute("x/i $pc", False, True), "insn #2")
gdb.execute("si")
report("lghi\t" in gdb.execute("x/i $pc", False, True), "insn #3")
report("lgrl\t" in gdb.execute("x/i $pc", False, True), "insn #3")
gdb.execute("si")
report("svc\t" in gdb.execute("x/i $pc", False, True), "insn #4")
gdb.execute("si")

View File

@ -8,7 +8,7 @@ _start:
/* puts("Hello, World!"); */
lghi %r2,1
larl %r3,foo
lghi %r4,foo_end-foo
lgrl %r4,foo_len
svc 4
/* exit(0); */
@ -18,3 +18,5 @@ svc 1
.align 2
foo: .asciz "Hello, World!\n"
foo_end:
.align 8
foo_len: .quad foo_end-foo

21
tests/tcg/s390x/larl.c Normal file
View File

@ -0,0 +1,21 @@
/*
* Test the LARL instruction.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <stdlib.h>
int main(void)
{
long algfi = (long)main;
long larl;
/*
* The compiler may emit larl for the C addition, so compute the expected
* value using algfi.
*/
asm("algfi %[r],0xd0000000" : [r] "+r" (algfi) : : "cc");
asm("larl %[r],main+0xd0000000" : [r] "=r" (larl));
return algfi == larl ? EXIT_SUCCESS : EXIT_FAILURE;
}

19
tests/tcg/s390x/lra.S Normal file
View File

@ -0,0 +1,19 @@
.org 0x200 /* lowcore padding */
.globl _start
_start:
lgrl %r1,initial_r1
lra %r1,0(%r1)
cgrl %r1,expected_r1
jne 1f
lpswe success_psw
1:
lpswe failure_psw
.align 8
initial_r1:
.quad 0x8765432112345678
expected_r1:
.quad 0x8765432180000038 /* ASCE type exception */
success_psw:
.quad 0x2000000000000,0xfff /* see is_special_wait_psw() */
failure_psw:
.quad 0x2000000000000,0 /* disabled wait */

30
tests/tcg/s390x/mdeb.c Normal file
View File

@ -0,0 +1,30 @@
/*
* Test the MDEB and MDEBR instructions.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <assert.h>
#include <stdlib.h>
int main(void)
{
union {
float f[2];
double d;
} a;
float b;
a.f[0] = 1.2345;
a.f[1] = 999;
b = 6.789;
asm("mdeb %[a],%[b]" : [a] "+f" (a.d) : [b] "R" (b));
assert(a.d > 8.38 && a.d < 8.39);
a.f[0] = 1.2345;
a.f[1] = 999;
b = 6.789;
asm("mdebr %[a],%[b]" : [a] "+f" (a.d) : [b] "f" (b));
assert(a.d > 8.38 && a.d < 8.39);
return EXIT_SUCCESS;
}

View File

@ -1,29 +1,55 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
static inline void mvcrl_8(const char *dst, const char *src)
static void mvcrl(const char *dst, const char *src, size_t len)
{
register long r0 asm("r0") = len;
asm volatile (
"llill %%r0, 8\n"
".insn sse, 0xE50A00000000, 0(%[dst]), 0(%[src])"
: : [dst] "d" (dst), [src] "d" (src)
: "r0", "memory");
: : [dst] "d" (dst), [src] "d" (src), "r" (r0)
: "memory");
}
int main(int argc, char *argv[])
static bool test(void)
{
const char *alpha = "abcdefghijklmnop";
/* array missing 'i' */
char tstr[17] = "abcdefghjklmnop\0" ;
char tstr[17] = "abcdefghjklmnop\0";
/* mvcrl reference use: 'open a hole in an array' */
mvcrl_8(tstr + 9, tstr + 8);
mvcrl(tstr + 9, tstr + 8, 8);
/* place missing 'i' */
tstr[8] = 'i';
return strncmp(alpha, tstr, 16ul);
return strncmp(alpha, tstr, 16ul) == 0;
}
static bool test_bad_r0(void)
{
char src[256] = { 0 };
/*
* PoP says: Bits 32-55 of general register 0 should contain zeros;
* otherwise, the program may not operate compatibly in the future.
*
* Try it anyway in order to check whether this would crash QEMU itself.
*/
mvcrl(src, src, (size_t)-1);
return true;
}
int main(void)
{
bool ok = true;
ok &= test();
ok &= test_bad_r0();
return ok ? EXIT_SUCCESS : EXIT_FAILURE;
}

View File

@ -12,9 +12,6 @@
*/
#include "qemu/osdep.h"
#include "qemu/config-file.h"
#include "qemu/option.h"
#include "qemu/module.h"
#include <dirent.h>
#include <sys/prctl.h>
#include <sched.h>
@ -147,21 +144,3 @@ void init_async_teardown(void)
clone(async_teardown_fn, new_stack_for_clone(), CLONE_VM, NULL);
sigprocmask(SIG_SETMASK, &old_signals, NULL);
}
static QemuOptsList qemu_run_with_opts = {
.name = "run-with",
.head = QTAILQ_HEAD_INITIALIZER(qemu_run_with_opts.head),
.desc = {
{
.name = "async-teardown",
.type = QEMU_OPT_BOOL,
},
{ /* end of list */ }
},
};
static void register_teardown(void)
{
qemu_add_opts(&qemu_run_with_opts);
}
opts_init(register_teardown);