* 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/kvm/
F: target/s390x/machine.c F: target/s390x/machine.c
F: target/s390x/sigp.c F: target/s390x/sigp.c
F: hw/s390x/pv.c
F: include/hw/s390x/pv.h
F: gdb-xml/s390*.xml F: gdb-xml/s390*.xml
T: git https://github.com/borntraeger/qemu.git s390-next T: git https://github.com/borntraeger/qemu.git s390-next
L: qemu-s390x@nongnu.org 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. Use ``-run-with async-teardown=on`` instead.
``-chroot`` (since 8.1)
'''''''''''''''''''''''
Use ``-run-with chroot=dir`` instead.
``-singlestep`` (since 8.1) ``-singlestep`` (since 8.1)
''''''''''''''''''''''''''' '''''''''''''''''''''''''''

View File

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

View File

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

View File

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

View File

@ -14,7 +14,7 @@
#include <linux/kvm.h> #include <linux/kvm.h>
#include "kvm/kvm_s390x.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-bus.h"
#include "hw/s390x/s390-pci-kvm.h" #include "hw/s390x/s390-pci-kvm.h"
#include "hw/s390x/s390-pci-inst.h" #include "hw/s390x/s390-pci-inst.h"

View File

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

View File

@ -13,7 +13,7 @@
#include "qemu/module.h" #include "qemu/module.h"
#include "sysemu/runstate.h" #include "sysemu/runstate.h"
#include "hw/s390x/tod.h" #include "hw/s390x/tod.h"
#include "hw/s390x/pv.h" #include "target/s390x/kvm/pv.h"
#include "kvm/kvm_s390x.h" #include "kvm/kvm_s390x.h"
static void kvm_s390_get_tod_raw(S390TOD *tod, Error **errp) 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) static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
{ {
regs->psw.addr = infop->entry; 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; 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') cc = meson.get_compiler('c')
all_languages = ['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'] all_languages += ['cpp']
cxx = meson.get_compiler('cpp') cxx = meson.get_compiler('cpp')
endif endif

View File

@ -38,6 +38,7 @@
#include "qemu/cutils.h" #include "qemu/cutils.h"
#include "qemu/config-file.h" #include "qemu/config-file.h"
#include "qemu/option.h" #include "qemu/option.h"
#include "qemu/module.h"
#ifdef CONFIG_LINUX #ifdef CONFIG_LINUX
#include <sys/prctl.h> #include <sys/prctl.h>
@ -148,6 +149,7 @@ int os_parse_cmd_args(int index, const char *optarg)
} }
break; break;
case QEMU_OPTION_chroot: case QEMU_OPTION_chroot:
warn_report("option is deprecated, use '-run-with chroot=...' instead");
chroot_dir = optarg; chroot_dir = optarg;
break; break;
case QEMU_OPTION_daemonize: case QEMU_OPTION_daemonize:
@ -158,18 +160,25 @@ int os_parse_cmd_args(int index, const char *optarg)
case QEMU_OPTION_asyncteardown: case QEMU_OPTION_asyncteardown:
init_async_teardown(); init_async_teardown();
break; break;
#endif
case QEMU_OPTION_run_with: { case QEMU_OPTION_run_with: {
const char *str;
QemuOpts *opts = qemu_opts_parse_noisily(qemu_find_opts("run-with"), QemuOpts *opts = qemu_opts_parse_noisily(qemu_find_opts("run-with"),
optarg, false); optarg, false);
if (!opts) { if (!opts) {
exit(1); exit(1);
} }
#if defined(CONFIG_LINUX)
if (qemu_opt_get_bool(opts, "async-teardown", false)) { if (qemu_opt_get_bool(opts, "async-teardown", false)) {
init_async_teardown(); init_async_teardown();
} }
#endif
str = qemu_opt_get(opts, "chroot");
if (str) {
chroot_dir = str;
}
break; break;
} }
#endif
default: default:
return -1; return -1;
} }
@ -348,3 +357,27 @@ int os_mlock(void)
return -ENOSYS; return -ENOSYS;
#endif #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 #ifndef _WIN32
DEF("chroot", HAS_ARG, QEMU_OPTION_chroot, \ 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) QEMU_ARCH_ALL)
#endif #endif
SRST SRST
``-chroot dir`` ``-chroot dir``
Deprecated, use '-run-with chroot=...' instead.
Immediately before starting guest execution, chroot to the specified Immediately before starting guest execution, chroot to the specified
directory. Especially useful in combination with -runas. directory. Especially useful in combination with -runas.
ERST ERST
@ -4868,13 +4869,16 @@ SRST
This option is deprecated and should no longer be used. The new option This option is deprecated and should no longer be used. The new option
``-run-with async-teardown=on`` is a replacement. ``-run-with async-teardown=on`` is a replacement.
ERST ERST
#endif
#ifdef CONFIG_POSIX
DEF("run-with", HAS_ARG, QEMU_OPTION_run_with, DEF("run-with", HAS_ARG, QEMU_OPTION_run_with,
"-run-with async-teardown[=on|off]\n" "-run-with [async-teardown=on|off][,chroot=dir]\n"
" misc QEMU process lifecycle options\n" " Set miscellaneous QEMU process lifecycle options:\n"
" async-teardown=on enables asynchronous teardown\n", " async-teardown=on enables asynchronous teardown (Linux only)\n"
" chroot=dir chroot to dir just before starting the VM\n",
QEMU_ARCH_ALL) QEMU_ARCH_ALL)
SRST SRST
``-run-with`` ``-run-with [async-teardown=on|off][,chroot=dir]``
Set QEMU process lifecycle options. Set QEMU process lifecycle options.
``async-teardown=on`` enables asynchronous teardown. A new process called ``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 performed correctly. This only works if the cleanup process is not
forcefully killed with SIGKILL before the main QEMU process has forcefully killed with SIGKILL before the main QEMU process has
terminated completely. 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 ERST
#endif #endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -24,7 +24,7 @@
#include "gdbstub/helpers.h" #include "gdbstub/helpers.h"
#include "qemu/timer.h" #include "qemu/timer.h"
#include "hw/s390x/ioinst.h" #include "hw/s390x/ioinst.h"
#include "hw/s390x/pv.h" #include "target/s390x/kvm/pv.h"
#include "sysemu/hw_accel.h" #include "sysemu/hw_accel.h"
#include "sysemu/runstate.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_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(ptlb, TCG_CALL_NO_RWG, void, env)
DEF_HELPER_FLAGS_1(purge, 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_1(per_check_exception, void, env)
DEF_HELPER_FLAGS_3(per_branch, TCG_CALL_NO_RWG, void, env, i64, i64) 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) 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 "hw/s390x/ioinst.h"
#include "trace.h" #include "trace.h"
#include "hw/s390x/s390-pci-bus.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 */ /* All I/O instructions but chsc use the s format */
static uint64_t get_address_from_regs(CPUS390XState *env, uint32_t ipb, static uint64_t get_address_from_regs(CPUS390XState *env, uint32_t ipb,

View File

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

View File

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

View File

@ -21,9 +21,9 @@
#include "qom/object_interfaces.h" #include "qom/object_interfaces.h"
#include "exec/confidential-guest-support.h" #include "exec/confidential-guest-support.h"
#include "hw/s390x/ipl.h" #include "hw/s390x/ipl.h"
#include "hw/s390x/pv.h"
#include "hw/s390x/sclp.h" #include "hw/s390x/sclp.h"
#include "target/s390x/kvm/kvm_s390x.h" #include "target/s390x/kvm/kvm_s390x.h"
#include "target/s390x/kvm/pv.h"
static bool info_valid; static bool info_valid;
static struct kvm_s390_pv_info_vm info_vm; 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; vaddr &= TARGET_PAGE_MASK;
if (!(env->psw.mask & PSW_MASK_DAT)) { if (rw != MMU_S390_LRA && !(env->psw.mask & PSW_MASK_DAT)) {
*raddr = vaddr; *raddr = vaddr;
goto nodat; 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 */ /* 64/32-bit FP multiplication */
uint64_t HELPER(mdeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 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); 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()); handle_exceptions(env, false, GETPC());
return ret; return ret;
} }

View File

@ -667,11 +667,11 @@
F(0xb317, MEEBR, RRE, Z, e1, e2, new, e1, meeb, 0, IF_BFP) 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(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(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(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(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(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) F(0xed07, MXDB, RXE, Z, f1, m2_64, new_x, x1, mxdb, 0, IF_BFP)
/* MULTIPLY HALFWORD */ /* MULTIPLY HALFWORD */
C(0x4c00, MH, RX_a, Z, r1_o, m2_16s, new, r1_32, mul, 0) 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; int32_t i;
/* MVCRL always copies one more byte than specified - maximum is 256 */ /* MVCRL always copies one more byte than specified - maximum is 256 */
l &= 0xff;
l++; l++;
access_prepare(&srca, env, src, l, MMU_DATA_LOAD, mmu_idx, ra); access_prepare(&srca, env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
@ -2355,7 +2356,7 @@ void HELPER(purge)(CPUS390XState *env)
} }
/* load real address */ /* 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 asc = env->psw.mask & PSW_MASK_ASC;
uint64_t ret, tec; 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); exc = mmu_translate(env, addr, MMU_S390_LRA, asc, &ret, &flags, &tec);
if (exc) { if (exc) {
cc = 3; cc = 3;
ret = exc | 0x80000000; ret = (r1 & 0xFFFFFFFF00000000ULL) | exc | 0x80000000;
} else { } else {
cc = 0; cc = 0;
ret |= addr & ~TARGET_PAGE_MASK; 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 r1 = get_field(s, r1);
int r2 = get_field(s, r2); int r2 = get_field(s, r2);
TCGv_i64 t = tcg_temp_new_i64(); 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 /* Note the "subsequently" in the PoO, which implies a defined result
if r1 == r2. Thus we cannot defer these writes to an output hook. */ 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_shri_i64(t, psw_mask, 32);
tcg_gen_deposit_i64(t, t, t_cc, 12, 2);
store_reg32_i64(r1, t); store_reg32_i64(r1, t);
if (r2 != 0) { if (r2 != 0) {
store_reg32_i64(r2, psw_mask); 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) 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); set_cc_static(s);
return DISAS_NEXT; return DISAS_NEXT;
} }
@ -5790,7 +5794,7 @@ static TCGv gen_ri2(DisasContext *s)
disas_jdest(s, i2, is_imm, imm, ri2); disas_jdest(s, i2, is_imm, imm, ri2);
if (is_imm) { 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; return ri2;

View File

@ -137,56 +137,9 @@ void migrate(QOSState *from, QOSState *to, const char *uri)
migrate_allocator(&from->alloc, &to->alloc); 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) 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) 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); G_GNUC_PRINTF(2, 3);
void qtest_common_shutdown(QOSState *qs); void qtest_common_shutdown(QOSState *qs);
void qtest_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 mkqcow2(const char *file, unsigned size_mb);
void migrate(QOSState *from, QOSState *to, const char *uri); void migrate(QOSState *from, QOSState *to, const char *uri);
void prepare_blkdebug_script(const char *debug_fn, const char *event); 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; 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); 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 #endif

View File

@ -46,6 +46,20 @@ static bool uffd_feature_thread_id;
static bool got_src_stop; static bool got_src_stop;
static bool got_dst_resume; 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 * Dirtylimit stop working if dirty page rate error
* value less than DIRTYLIMIT_TOLERANCE_RANGE * 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); 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) static void migrate_pause(QTestState *who)
{ {
qtest_qmp_assert_success(who, "{ 'execute': 'migrate-pause' }"); qtest_qmp_assert_success(who, "{ 'execute': 'migrate-pause' }");
@ -577,7 +676,10 @@ typedef struct {
MIG_TEST_FAIL_DEST_QUIT_ERR, MIG_TEST_FAIL_DEST_QUIT_ERR,
} result; } 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; unsigned int iterations;
/* /*
@ -1165,12 +1267,14 @@ static int migrate_postcopy_prepare(QTestState **from_ptr,
migrate_ensure_non_converge(from); migrate_ensure_non_converge(from);
migrate_prepare_for_dirty_mem(from);
/* Wait for the first serial output from the source */ /* Wait for the first serial output from the source */
wait_for_serial("src_serial"); wait_for_serial("src_serial");
migrate_qmp(from, uri, "{}"); migrate_qmp(from, uri, "{}");
wait_for_migration_pass(from); migrate_wait_for_dirty_mem(from, to);
*from_ptr = from; *from_ptr = from;
*to_ptr = to; *to_ptr = to;
@ -1405,14 +1509,8 @@ static void test_precopy_common(MigrateCommon *args)
} }
if (args->live) { 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_ensure_non_converge(from);
migrate_prepare_for_dirty_mem(from);
} else { } else {
/* /*
* Testing non-live migration, we allow it to run at * Testing non-live migration, we allow it to run at
@ -1447,13 +1545,16 @@ static void test_precopy_common(MigrateCommon *args)
} }
} else { } else {
if (args->live) { if (args->live) {
if (args->iterations) { /*
while (args->iterations--) { * For initial iteration(s) we must do a full pass,
wait_for_migration_pass(from); * but for the final iteration, we need only wait
} * for some dirty mem before switching to converge
} else { */
while (args->iterations > 1) {
wait_for_migration_pass(from); wait_for_migration_pass(from);
args->iterations--;
} }
migrate_wait_for_dirty_mem(from, to);
migrate_ensure_converge(from); migrate_ensure_converge(from);
@ -1586,6 +1687,9 @@ static void test_ignore_shared(void)
return; return;
} }
migrate_ensure_non_converge(from);
migrate_prepare_for_dirty_mem(from);
migrate_set_capability(from, "x-ignore-shared", true); migrate_set_capability(from, "x-ignore-shared", true);
migrate_set_capability(to, "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, "{}"); migrate_qmp(from, uri, "{}");
wait_for_migration_pass(from); migrate_wait_for_dirty_mem(from, to);
if (!got_src_stop) { if (!got_src_stop) {
qtest_qmp_eventwait(from, "STOP"); qtest_qmp_eventwait(from, "STOP");
@ -2325,6 +2429,7 @@ static void test_multifd_tcp_cancel(void)
} }
migrate_ensure_non_converge(from); migrate_ensure_non_converge(from);
migrate_prepare_for_dirty_mem(from);
migrate_set_parameter_int(from, "multifd-channels", 16); migrate_set_parameter_int(from, "multifd-channels", 16);
migrate_set_parameter_int(to, "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, "{}"); migrate_qmp(from, uri, "{}");
wait_for_migration_pass(from); migrate_wait_for_dirty_mem(from, to);
migrate_cancel(from); migrate_cancel(from);
@ -2372,11 +2477,13 @@ static void test_multifd_tcp_cancel(void)
wait_for_migration_status(from, "cancelled", NULL); wait_for_migration_status(from, "cancelled", NULL);
migrate_ensure_converge(from); migrate_ensure_non_converge(from);
migrate_qmp(from, uri, "{}"); migrate_qmp(from, uri, "{}");
wait_for_migration_pass(from); migrate_wait_for_dirty_mem(from, to);
migrate_ensure_converge(from);
if (!got_src_stop) { if (!got_src_stop) {
qtest_qmp_eventwait(from, "STOP"); qtest_qmp_eventwait(from, "STOP");

View File

@ -48,7 +48,7 @@ static QTestState *qtest_init_with_config(const char *cfgdata)
return qts; 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; Visitor *v;
g_autoptr(MemdevList) memdevs = NULL; g_autoptr(MemdevList) memdevs = NULL;
@ -63,8 +63,8 @@ static void test_x86_memdev_resp(QObject *res)
g_assert(!memdevs->next); g_assert(!memdevs->next);
memdev = memdevs->value; memdev = memdevs->value;
g_assert_cmpstr(memdev->id, ==, "ram"); g_assert_cmpstr(memdev->id, ==, mem_id);
g_assert_cmpint(memdev->size, ==, 200 * MiB); g_assert_cmpint(memdev->size, ==, size * MiB);
visit_free(v); visit_free(v);
} }
@ -80,7 +80,7 @@ static void test_x86_memdev(void)
qts = qtest_init_with_config(cfgdata); qts = qtest_init_with_config(cfgdata);
/* Test valid command */ /* Test valid command */
resp = qtest_qmp(qts, "{ 'execute': 'query-memdev' }"); 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); qobject_unref(resp);
qtest_quit(qts); qtest_quit(qts);
@ -197,6 +197,189 @@ static void test_docs_config_ich9(void)
qtest_quit(qts); 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[]) int main(int argc, char *argv[])
{ {
const char *arch; const char *arch;
@ -211,6 +394,19 @@ int main(int argc, char *argv[])
qtest_has_device("ich9-usb-uhci1")) { qtest_has_device("ich9-usb-uhci1")) {
qtest_add_func("readconfig/x86/ich9-ehci-uhci", test_docs_config_ich9); 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__) #if defined(CONFIG_SPICE) && !defined(__FreeBSD__)
qtest_add_func("readconfig/spice", test_spice); qtest_add_func("readconfig/spice", test_spice);

View File

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

View File

@ -36,6 +36,9 @@ TESTS+=rxsbg
TESTS+=ex-relative-long TESTS+=ex-relative-long
TESTS+=ex-branch TESTS+=ex-branch
TESTS+=mxdb TESTS+=mxdb
TESTS+=epsw
TESTS+=larl
TESTS+=mdeb
cdsg: CFLAGS+=-pthread cdsg: CFLAGS+=-pthread
cdsg: LDFLAGS+=-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") gdb.execute("si")
report("larl\t" in gdb.execute("x/i $pc", False, True), "insn #2") report("larl\t" in gdb.execute("x/i $pc", False, True), "insn #2")
gdb.execute("si") 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") gdb.execute("si")
report("svc\t" in gdb.execute("x/i $pc", False, True), "insn #4") report("svc\t" in gdb.execute("x/i $pc", False, True), "insn #4")
gdb.execute("si") gdb.execute("si")

View File

@ -8,7 +8,7 @@ _start:
/* puts("Hello, World!"); */ /* puts("Hello, World!"); */
lghi %r2,1 lghi %r2,1
larl %r3,foo larl %r3,foo
lghi %r4,foo_end-foo lgrl %r4,foo_len
svc 4 svc 4
/* exit(0); */ /* exit(0); */
@ -18,3 +18,5 @@ svc 1
.align 2 .align 2
foo: .asciz "Hello, World!\n" foo: .asciz "Hello, World!\n"
foo_end: 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 <stdint.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
static void mvcrl(const char *dst, const char *src, size_t len)
static inline void mvcrl_8(const char *dst, const char *src)
{ {
register long r0 asm("r0") = len;
asm volatile ( asm volatile (
"llill %%r0, 8\n"
".insn sse, 0xE50A00000000, 0(%[dst]), 0(%[src])" ".insn sse, 0xE50A00000000, 0(%[dst]), 0(%[src])"
: : [dst] "d" (dst), [src] "d" (src) : : [dst] "d" (dst), [src] "d" (src), "r" (r0)
: "r0", "memory"); : "memory");
} }
static bool test(void)
int main(int argc, char *argv[])
{ {
const char *alpha = "abcdefghijklmnop"; const char *alpha = "abcdefghijklmnop";
/* array missing 'i' */ /* array missing 'i' */
char tstr[17] = "abcdefghjklmnop\0" ; char tstr[17] = "abcdefghjklmnop\0";
/* mvcrl reference use: 'open a hole in an array' */ /* mvcrl reference use: 'open a hole in an array' */
mvcrl_8(tstr + 9, tstr + 8); mvcrl(tstr + 9, tstr + 8, 8);
/* place missing 'i' */ /* place missing 'i' */
tstr[8] = '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/osdep.h"
#include "qemu/config-file.h"
#include "qemu/option.h"
#include "qemu/module.h"
#include <dirent.h> #include <dirent.h>
#include <sys/prctl.h> #include <sys/prctl.h>
#include <sched.h> #include <sched.h>
@ -147,21 +144,3 @@ void init_async_teardown(void)
clone(async_teardown_fn, new_stack_for_clone(), CLONE_VM, NULL); clone(async_teardown_fn, new_stack_for_clone(), CLONE_VM, NULL);
sigprocmask(SIG_SETMASK, &old_signals, 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);