mirror of https://github.com/xemu-project/xemu.git
* 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:
commit
8d309a3a97
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
'''''''''''''''''''''''''''
|
'''''''''''''''''''''''''''
|
||||||
|
|
||||||
|
|
|
@ -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 = .....
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
35
os-posix.c
35
os-posix.c
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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];
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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) \
|
||||||
|
|
|
@ -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) \
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -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;
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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")
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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 */
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
|
|
Loading…
Reference in New Issue