mirror of https://github.com/xemu-project/xemu.git
A selection of s390x patches:
- cleanups, fixes and improvements - program check loop detection (useful with the corresponding kernel patch) - wire up virtio-crypto for ccw - and finally support many virtqueues for virtio-ccw -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJYr/qXAAoJEN7Pa5PG8C+vzSYP+wR/mA4wmXh0Jj8zzxeJaeQa UNNwR7Ege4KjdL0DKXw/Uy2S/H2qGZvD4cb3JLIwp15BSilmcxRGS+v18ooBuRtx X8+W2peH/Ldk4SAGbfXyRR4EXom4ZmmHtgdoWYPUhgq2BimH1vBcY06uHOkJ4zTP vBfpmvKL53SjjHF6b9NmlprSDrn8cbQgqqxTWc0YL0aEcFTcxpBfr98dCfrNfk8b k6f324hY+3YC7rdvLAsBx3tNjDmEoEh4aidGyECKOWiy2Bt2hQ/ZhxVUk7cFV30M F0mttRJSxuBY9xYfmuxTKkm2ttIH0BiOhFmE5+YEj7ot+iqBslyYHR2prkZC66v+ wQ9Ynx8ys0ec/IkHx2uIt8iOdAiq/K5gJkyjEw6ekg70OOGrTtyv5y6G9FOc4B4W ms7eUnhIgr5rEv/oQgCSgCUlAUm6MWW/BtffqmKZ7M2/7l8Y3T1U4f9383sKZtIT 7xr/AtV30yH695r+bllEljIjgMU5EWUDpA2kBCC6tzJQ0KYSoICSGloxKNEK3Z6X EsYby7YjLArTlvsLJ4y2k/BPzcM4IYJX9NDjCmMRpR2I46Nb35uwR73EZx6JS6fw dKmdx0qSZbaMbmwIJZzVz4kzG9z6gePkCvaEmPa99ZgnaZ0igm4y5W6Q8fLEn1Jz zy277Wciim5mnZWuJAbl =uM3N -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20170224' into staging A selection of s390x patches: - cleanups, fixes and improvements - program check loop detection (useful with the corresponding kernel patch) - wire up virtio-crypto for ccw - and finally support many virtqueues for virtio-ccw # gpg: Signature made Fri 24 Feb 2017 09:19:19 GMT # gpg: using RSA key 0xDECF6B93C6F02FAF # gpg: Good signature from "Cornelia Huck <huckc@linux.vnet.ibm.com>" # gpg: aka "Cornelia Huck <cornelia.huck@de.ibm.com>" # Primary key fingerprint: C3D0 D66D C362 4FF6 A8C0 18CE DECF 6B93 C6F0 2FAF * remotes/cohuck/tags/s390x-20170224: s390x/css: handle format-0 TIC CCW correctly s390x/arch_dump: pass cpuid into notes sections s390x/arch_dump: use proper note name and note size virtio-ccw: support VIRTIO_QUEUE_MAX virtqueues s390x: bump ADAPTER_ROUTES_MAX_GSI virtio-ccw: check flic->adapter_routes_max_batch s390x: add property adapter_routes_max_batch virtio-ccw: Check the number of vqs in CCW_CMD_SET_IND virtio-ccw: add virtio-crypto-ccw device virtio-ccw: handle virtio 1 only devices s390x/flic: fail migration on source already s390x/kvm: detect some program check loops s390x/s390-virtio: get rid of DPRINTF Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
2421f381dc
|
@ -16,6 +16,8 @@
|
|||
#include "migration/qemu-file.h"
|
||||
#include "hw/s390x/s390_flic.h"
|
||||
#include "trace.h"
|
||||
#include "hw/qdev.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
S390FLICState *s390_get_flic(void)
|
||||
{
|
||||
|
@ -85,6 +87,30 @@ static void qemu_s390_flic_class_init(ObjectClass *oc, void *data)
|
|||
fsc->clear_io_irq = qemu_s390_clear_io_flic;
|
||||
}
|
||||
|
||||
static Property s390_flic_common_properties[] = {
|
||||
DEFINE_PROP_UINT32("adapter_routes_max_batch", S390FLICState,
|
||||
adapter_routes_max_batch, ADAPTER_ROUTES_MAX_GSI),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void s390_flic_common_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
uint32_t max_batch = S390_FLIC_COMMON(dev)->adapter_routes_max_batch;
|
||||
|
||||
if (max_batch > ADAPTER_ROUTES_MAX_GSI) {
|
||||
error_setg(errp, "flic adapter_routes_max_batch too big"
|
||||
"%d (%d allowed)", max_batch, ADAPTER_ROUTES_MAX_GSI);
|
||||
}
|
||||
}
|
||||
|
||||
static void s390_flic_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->props = s390_flic_common_properties;
|
||||
dc->realize = s390_flic_common_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo qemu_s390_flic_info = {
|
||||
.name = TYPE_QEMU_S390_FLIC,
|
||||
.parent = TYPE_S390_FLIC_COMMON,
|
||||
|
@ -92,10 +118,12 @@ static const TypeInfo qemu_s390_flic_info = {
|
|||
.class_init = qemu_s390_flic_class_init,
|
||||
};
|
||||
|
||||
|
||||
static const TypeInfo s390_flic_common_info = {
|
||||
.name = TYPE_S390_FLIC_COMMON,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(S390FLICState),
|
||||
.class_init = s390_flic_class_init,
|
||||
.class_size = sizeof(S390FLICStateClass),
|
||||
};
|
||||
|
||||
|
|
|
@ -293,6 +293,7 @@ static int kvm_flic_save(QEMUFile *f, void *opaque, size_t size,
|
|||
int len = FLIC_SAVE_INITIAL_SIZE;
|
||||
void *buf;
|
||||
int count;
|
||||
int r = 0;
|
||||
|
||||
flic_disable_wait_pfault((struct KVMS390FLICState *) opaque);
|
||||
|
||||
|
@ -303,7 +304,7 @@ static int kvm_flic_save(QEMUFile *f, void *opaque, size_t size,
|
|||
* migration state */
|
||||
error_report("flic: couldn't allocate memory");
|
||||
qemu_put_be64(f, FLIC_FAILED);
|
||||
return 0;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
count = __get_all_irqs(flic, &buf, len);
|
||||
|
@ -314,6 +315,7 @@ static int kvm_flic_save(QEMUFile *f, void *opaque, size_t size,
|
|||
* target system to fail when attempting to load irqs from the
|
||||
* migration state */
|
||||
qemu_put_be64(f, FLIC_FAILED);
|
||||
r = count;
|
||||
} else {
|
||||
qemu_put_be64(f, count);
|
||||
qemu_put_buffer(f, (uint8_t *) buf,
|
||||
|
@ -321,7 +323,7 @@ static int kvm_flic_save(QEMUFile *f, void *opaque, size_t size,
|
|||
}
|
||||
g_free(buf);
|
||||
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -368,13 +368,16 @@ static CCW1 copy_ccw_from_guest(hwaddr addr, bool fmt1)
|
|||
ret.cda = be32_to_cpu(tmp1.cda);
|
||||
} else {
|
||||
cpu_physical_memory_read(addr, &tmp0, sizeof(tmp0));
|
||||
ret.cmd_code = tmp0.cmd_code;
|
||||
ret.flags = tmp0.flags;
|
||||
ret.count = be16_to_cpu(tmp0.count);
|
||||
ret.cda = be16_to_cpu(tmp0.cda1) | (tmp0.cda0 << 16);
|
||||
if ((ret.cmd_code & 0x0f) == CCW_CMD_TIC) {
|
||||
ret.cmd_code &= 0x0f;
|
||||
if ((tmp0.cmd_code & 0x0f) == CCW_CMD_TIC) {
|
||||
ret.cmd_code = CCW_CMD_TIC;
|
||||
ret.flags = 0;
|
||||
ret.count = 0;
|
||||
} else {
|
||||
ret.cmd_code = tmp0.cmd_code;
|
||||
ret.flags = tmp0.flags;
|
||||
ret.count = be16_to_cpu(tmp0.count);
|
||||
}
|
||||
ret.cda = be16_to_cpu(tmp0.cda1) | (tmp0.cda0 << 16);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ static int virtio_ccw_hcall_notify(const uint64_t *args)
|
|||
if (!sch || !css_subch_visible(sch)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (queue >= VIRTIO_CCW_QUEUE_MAX) {
|
||||
if (queue >= VIRTIO_QUEUE_MAX) {
|
||||
return -EINVAL;
|
||||
}
|
||||
virtio_queue_notify(virtio_ccw_get_vdev(sch), queue);
|
||||
|
@ -336,7 +336,12 @@ static const TypeInfo ccw_machine_info = {
|
|||
type_init(ccw_machine_register_##suffix)
|
||||
|
||||
#define CCW_COMPAT_2_8 \
|
||||
HW_COMPAT_2_8
|
||||
HW_COMPAT_2_8 \
|
||||
{\
|
||||
.driver = TYPE_S390_FLIC_COMMON,\
|
||||
.property = "adapter_routes_max_batch",\
|
||||
.value = "64",\
|
||||
},
|
||||
|
||||
#define CCW_COMPAT_2_7 \
|
||||
HW_COMPAT_2_7
|
||||
|
|
|
@ -44,16 +44,6 @@
|
|||
#include "hw/s390x/ipl.h"
|
||||
#include "cpu.h"
|
||||
|
||||
//#define DEBUG_S390
|
||||
|
||||
#ifdef DEBUG_S390
|
||||
#define DPRINTF(fmt, ...) \
|
||||
do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
|
||||
#else
|
||||
#define DPRINTF(fmt, ...) \
|
||||
do { } while (0)
|
||||
#endif
|
||||
|
||||
#define MAX_BLK_DEVS 10
|
||||
|
||||
#define S390_TOD_CLOCK_VALUE_MISSING 0x00
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
#include "trace.h"
|
||||
#include "hw/s390x/css-bridge.h"
|
||||
|
||||
#define NR_CLASSIC_INDICATOR_BITS 64
|
||||
|
||||
static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size,
|
||||
VirtioCcwDevice *dev);
|
||||
|
||||
|
@ -126,7 +128,7 @@ static int virtio_ccw_set_vqs(SubchDev *sch, VqInfoBlock *info,
|
|||
uint16_t num = info ? info->num : linfo->num;
|
||||
uint64_t desc = info ? info->desc : linfo->queue;
|
||||
|
||||
if (index >= VIRTIO_CCW_QUEUE_MAX) {
|
||||
if (index >= VIRTIO_QUEUE_MAX) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -162,7 +164,7 @@ static int virtio_ccw_set_vqs(SubchDev *sch, VqInfoBlock *info,
|
|||
virtio_queue_set_vector(vdev, index, index);
|
||||
}
|
||||
/* tell notify handler in case of config change */
|
||||
vdev->config_vector = VIRTIO_CCW_QUEUE_MAX;
|
||||
vdev->config_vector = VIRTIO_QUEUE_MAX;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -280,6 +282,15 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
|||
ccw.cmd_code);
|
||||
check_len = !((ccw.flags & CCW_FLAG_SLI) && !(ccw.flags & CCW_FLAG_DC));
|
||||
|
||||
if (dev->force_revision_1 && dev->revision < 0 &&
|
||||
ccw.cmd_code != CCW_CMD_SET_VIRTIO_REV) {
|
||||
/*
|
||||
* virtio-1 drivers must start with negotiating to a revision >= 1,
|
||||
* so post a command reject for all other commands
|
||||
*/
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/* Look at the command. */
|
||||
switch (ccw.cmd_code) {
|
||||
case CCW_CMD_SET_VQ:
|
||||
|
@ -500,6 +511,11 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
|||
ret = -ENOSYS;
|
||||
break;
|
||||
}
|
||||
if (virtio_get_num_queues(vdev) > NR_CLASSIC_INDICATOR_BITS) {
|
||||
/* More queues than indicator bits --> trigger a reject */
|
||||
ret = -ENOSYS;
|
||||
break;
|
||||
}
|
||||
if (!ccw.cda) {
|
||||
ret = -EFAULT;
|
||||
} else {
|
||||
|
@ -549,7 +565,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
|||
ccw.cda,
|
||||
MEMTXATTRS_UNSPECIFIED,
|
||||
NULL);
|
||||
if (vq_config.index >= VIRTIO_CCW_QUEUE_MAX) {
|
||||
if (vq_config.index >= VIRTIO_QUEUE_MAX) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
@ -638,7 +654,8 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
|||
* need to fetch it here. Nothing to do for now, though.
|
||||
*/
|
||||
if (dev->revision >= 0 ||
|
||||
revinfo.revision > virtio_ccw_rev_max(dev)) {
|
||||
revinfo.revision > virtio_ccw_rev_max(dev) ||
|
||||
(dev->force_revision_1 && !revinfo.revision)) {
|
||||
ret = -ENOSYS;
|
||||
break;
|
||||
}
|
||||
|
@ -669,6 +686,12 @@ static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp)
|
|||
if (!sch) {
|
||||
return;
|
||||
}
|
||||
if (!virtio_ccw_rev_max(dev) && dev->force_revision_1) {
|
||||
error_setg(&err, "Invalid value of property max_rev "
|
||||
"(is %d expected >= 1)", virtio_ccw_rev_max(dev));
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
sch->driver_data = dev;
|
||||
sch->ccw_cb = virtio_ccw_cb;
|
||||
|
@ -878,6 +901,24 @@ static void virtio_ccw_rng_realize(VirtioCcwDevice *ccw_dev, Error **errp)
|
|||
NULL);
|
||||
}
|
||||
|
||||
static void virtio_ccw_crypto_realize(VirtioCcwDevice *ccw_dev, Error **errp)
|
||||
{
|
||||
VirtIOCryptoCcw *dev = VIRTIO_CRYPTO_CCW(ccw_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
Error *err = NULL;
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
object_property_set_link(OBJECT(vdev),
|
||||
OBJECT(dev->vdev.conf.cryptodev), "cryptodev",
|
||||
NULL);
|
||||
}
|
||||
|
||||
/* DeviceState to VirtioCcwDevice. Note: used on datapath,
|
||||
* be careful and test performance if you change this.
|
||||
*/
|
||||
|
@ -919,11 +960,11 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
|
|||
uint64_t indicators;
|
||||
|
||||
/* queue indicators + secondary indicators */
|
||||
if (vector >= VIRTIO_CCW_QUEUE_MAX + 64) {
|
||||
if (vector >= VIRTIO_QUEUE_MAX + 64) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (vector < VIRTIO_CCW_QUEUE_MAX) {
|
||||
if (vector < VIRTIO_QUEUE_MAX) {
|
||||
if (!dev->indicators) {
|
||||
return;
|
||||
}
|
||||
|
@ -1278,15 +1319,22 @@ static void virtio_ccw_device_plugged(DeviceState *d, Error **errp)
|
|||
CcwDevice *ccw_dev = CCW_DEVICE(d);
|
||||
SubchDev *sch = ccw_dev->sch;
|
||||
int n = virtio_get_num_queues(vdev);
|
||||
S390FLICState *flic = s390_get_flic();
|
||||
|
||||
if (!virtio_has_feature(vdev->host_features, VIRTIO_F_VERSION_1)) {
|
||||
dev->max_rev = 0;
|
||||
}
|
||||
|
||||
if (virtio_get_num_queues(vdev) > VIRTIO_CCW_QUEUE_MAX) {
|
||||
if (virtio_get_num_queues(vdev) > VIRTIO_QUEUE_MAX) {
|
||||
error_setg(errp, "The number of virtqueues %d "
|
||||
"exceeds ccw limit %d", n,
|
||||
VIRTIO_CCW_QUEUE_MAX);
|
||||
"exceeds virtio limit %d", n,
|
||||
VIRTIO_QUEUE_MAX);
|
||||
return;
|
||||
}
|
||||
if (virtio_get_num_queues(vdev) > flic->adapter_routes_max_batch) {
|
||||
error_setg(errp, "The number of virtqueues %d "
|
||||
"exceeds flic adapter route limit %d", n,
|
||||
flic->adapter_routes_max_batch);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1518,6 +1566,48 @@ static const TypeInfo virtio_ccw_rng = {
|
|||
.class_init = virtio_ccw_rng_class_init,
|
||||
};
|
||||
|
||||
static Property virtio_ccw_crypto_properties[] = {
|
||||
DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id),
|
||||
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
|
||||
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
|
||||
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
|
||||
VIRTIO_CCW_MAX_REV),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void virtio_ccw_crypto_instance_init(Object *obj)
|
||||
{
|
||||
VirtIOCryptoCcw *dev = VIRTIO_CRYPTO_CCW(obj);
|
||||
VirtioCcwDevice *ccw_dev = VIRTIO_CCW_DEVICE(obj);
|
||||
|
||||
ccw_dev->force_revision_1 = true;
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VIRTIO_CRYPTO);
|
||||
|
||||
object_property_add_alias(obj, "cryptodev", OBJECT(&dev->vdev),
|
||||
"cryptodev", &error_abort);
|
||||
}
|
||||
|
||||
static void virtio_ccw_crypto_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
|
||||
|
||||
k->realize = virtio_ccw_crypto_realize;
|
||||
k->exit = virtio_ccw_exit;
|
||||
dc->reset = virtio_ccw_reset;
|
||||
dc->props = virtio_ccw_crypto_properties;
|
||||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||
}
|
||||
|
||||
static const TypeInfo virtio_ccw_crypto = {
|
||||
.name = TYPE_VIRTIO_CRYPTO_CCW,
|
||||
.parent = TYPE_VIRTIO_CCW_DEVICE,
|
||||
.instance_size = sizeof(VirtIOCryptoCcw),
|
||||
.instance_init = virtio_ccw_crypto_instance_init,
|
||||
.class_init = virtio_ccw_crypto_class_init,
|
||||
};
|
||||
|
||||
static void virtio_ccw_busdev_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev;
|
||||
|
@ -1720,6 +1810,7 @@ static void virtio_ccw_register(void)
|
|||
#ifdef CONFIG_VHOST_VSOCK
|
||||
type_register_static(&vhost_vsock_ccw_info);
|
||||
#endif
|
||||
type_register_static(&virtio_ccw_crypto);
|
||||
}
|
||||
|
||||
type_init(virtio_ccw_register)
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#endif
|
||||
#include "hw/virtio/virtio-balloon.h"
|
||||
#include "hw/virtio/virtio-rng.h"
|
||||
#include "hw/virtio/virtio-crypto.h"
|
||||
#include "hw/virtio/virtio-bus.h"
|
||||
#ifdef CONFIG_VHOST_VSOCK
|
||||
#include "hw/virtio/vhost-vsock.h"
|
||||
|
@ -94,6 +95,7 @@ struct VirtioCcwDevice {
|
|||
IndAddr *indicators2;
|
||||
IndAddr *summary_indicator;
|
||||
uint64_t ind_bit;
|
||||
bool force_revision_1;
|
||||
};
|
||||
|
||||
/* The maximum virtio revision we support. */
|
||||
|
@ -182,6 +184,17 @@ typedef struct VirtIORNGCcw {
|
|||
VirtIORNG vdev;
|
||||
} VirtIORNGCcw;
|
||||
|
||||
/* virtio-crypto-ccw */
|
||||
|
||||
#define TYPE_VIRTIO_CRYPTO_CCW "virtio-crypto-ccw"
|
||||
#define VIRTIO_CRYPTO_CCW(obj) \
|
||||
OBJECT_CHECK(VirtIOCryptoCcw, (obj), TYPE_VIRTIO_CRYPTO_CCW)
|
||||
|
||||
typedef struct VirtIOCryptoCcw {
|
||||
VirtioCcwDevice parent_obj;
|
||||
VirtIOCrypto vdev;
|
||||
} VirtIOCryptoCcw;
|
||||
|
||||
VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch);
|
||||
|
||||
#ifdef CONFIG_VIRTFS
|
||||
|
|
|
@ -17,8 +17,13 @@
|
|||
#include "hw/s390x/adapter.h"
|
||||
#include "hw/virtio/virtio.h"
|
||||
|
||||
#define ADAPTER_ROUTES_MAX_GSI 64
|
||||
#define VIRTIO_CCW_QUEUE_MAX ADAPTER_ROUTES_MAX_GSI
|
||||
/*
|
||||
* Reserve enough gsis to accommodate all virtio devices.
|
||||
* If any other user of adapter routes needs more of these,
|
||||
* we need to bump the value; but virtio looks like the
|
||||
* maximum right now.
|
||||
*/
|
||||
#define ADAPTER_ROUTES_MAX_GSI VIRTIO_QUEUE_MAX
|
||||
|
||||
typedef struct AdapterRoutes {
|
||||
AdapterInfo adapter;
|
||||
|
@ -32,6 +37,8 @@ typedef struct AdapterRoutes {
|
|||
|
||||
typedef struct S390FLICState {
|
||||
SysBusDevice parent_obj;
|
||||
/* to limit AdapterRoutes.num_routes for compat */
|
||||
uint32_t adapter_routes_max_batch;
|
||||
|
||||
} S390FLICState;
|
||||
|
||||
|
|
|
@ -59,8 +59,7 @@ typedef struct S390xElfVregsHiStruct S390xElfVregsHi;
|
|||
|
||||
typedef struct noteStruct {
|
||||
Elf64_Nhdr hdr;
|
||||
char name[5];
|
||||
char pad3[3];
|
||||
char name[8];
|
||||
union {
|
||||
S390xElfPrstatus prstatus;
|
||||
S390xElfFpregset fpregset;
|
||||
|
@ -74,7 +73,7 @@ typedef struct noteStruct {
|
|||
} contents;
|
||||
} QEMU_PACKED Note;
|
||||
|
||||
static void s390x_write_elf64_prstatus(Note *note, S390CPU *cpu)
|
||||
static void s390x_write_elf64_prstatus(Note *note, S390CPU *cpu, int id)
|
||||
{
|
||||
int i;
|
||||
S390xUserRegs *regs;
|
||||
|
@ -88,9 +87,10 @@ static void s390x_write_elf64_prstatus(Note *note, S390CPU *cpu)
|
|||
regs->acrs[i] = cpu_to_be32(cpu->env.aregs[i]);
|
||||
regs->gprs[i] = cpu_to_be64(cpu->env.regs[i]);
|
||||
}
|
||||
note->contents.prstatus.pid = id;
|
||||
}
|
||||
|
||||
static void s390x_write_elf64_fpregset(Note *note, S390CPU *cpu)
|
||||
static void s390x_write_elf64_fpregset(Note *note, S390CPU *cpu, int id)
|
||||
{
|
||||
int i;
|
||||
CPUS390XState *cs = &cpu->env;
|
||||
|
@ -102,7 +102,7 @@ static void s390x_write_elf64_fpregset(Note *note, S390CPU *cpu)
|
|||
}
|
||||
}
|
||||
|
||||
static void s390x_write_elf64_vregslo(Note *note, S390CPU *cpu)
|
||||
static void s390x_write_elf64_vregslo(Note *note, S390CPU *cpu, int id)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -112,7 +112,7 @@ static void s390x_write_elf64_vregslo(Note *note, S390CPU *cpu)
|
|||
}
|
||||
}
|
||||
|
||||
static void s390x_write_elf64_vregshi(Note *note, S390CPU *cpu)
|
||||
static void s390x_write_elf64_vregshi(Note *note, S390CPU *cpu, int id)
|
||||
{
|
||||
int i;
|
||||
S390xElfVregsHi *temp_vregshi;
|
||||
|
@ -126,25 +126,25 @@ static void s390x_write_elf64_vregshi(Note *note, S390CPU *cpu)
|
|||
}
|
||||
}
|
||||
|
||||
static void s390x_write_elf64_timer(Note *note, S390CPU *cpu)
|
||||
static void s390x_write_elf64_timer(Note *note, S390CPU *cpu, int id)
|
||||
{
|
||||
note->hdr.n_type = cpu_to_be32(NT_S390_TIMER);
|
||||
note->contents.timer = cpu_to_be64((uint64_t)(cpu->env.cputm));
|
||||
}
|
||||
|
||||
static void s390x_write_elf64_todcmp(Note *note, S390CPU *cpu)
|
||||
static void s390x_write_elf64_todcmp(Note *note, S390CPU *cpu, int id)
|
||||
{
|
||||
note->hdr.n_type = cpu_to_be32(NT_S390_TODCMP);
|
||||
note->contents.todcmp = cpu_to_be64((uint64_t)(cpu->env.ckc));
|
||||
}
|
||||
|
||||
static void s390x_write_elf64_todpreg(Note *note, S390CPU *cpu)
|
||||
static void s390x_write_elf64_todpreg(Note *note, S390CPU *cpu, int id)
|
||||
{
|
||||
note->hdr.n_type = cpu_to_be32(NT_S390_TODPREG);
|
||||
note->contents.todpreg = cpu_to_be32((uint32_t)(cpu->env.todpr));
|
||||
}
|
||||
|
||||
static void s390x_write_elf64_ctrs(Note *note, S390CPU *cpu)
|
||||
static void s390x_write_elf64_ctrs(Note *note, S390CPU *cpu, int id)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -155,20 +155,26 @@ static void s390x_write_elf64_ctrs(Note *note, S390CPU *cpu)
|
|||
}
|
||||
}
|
||||
|
||||
static void s390x_write_elf64_prefix(Note *note, S390CPU *cpu)
|
||||
static void s390x_write_elf64_prefix(Note *note, S390CPU *cpu, int id)
|
||||
{
|
||||
note->hdr.n_type = cpu_to_be32(NT_S390_PREFIX);
|
||||
note->contents.prefix = cpu_to_be32((uint32_t)(cpu->env.psa));
|
||||
}
|
||||
|
||||
|
||||
static const struct NoteFuncDescStruct {
|
||||
typedef struct NoteFuncDescStruct {
|
||||
int contents_size;
|
||||
void (*note_contents_func)(Note *note, S390CPU *cpu);
|
||||
} note_func[] = {
|
||||
void (*note_contents_func)(Note *note, S390CPU *cpu, int id);
|
||||
} NoteFuncDesc;
|
||||
|
||||
static const NoteFuncDesc note_core[] = {
|
||||
{sizeof(((Note *)0)->contents.prstatus), s390x_write_elf64_prstatus},
|
||||
{sizeof(((Note *)0)->contents.prefix), s390x_write_elf64_prefix},
|
||||
{sizeof(((Note *)0)->contents.fpregset), s390x_write_elf64_fpregset},
|
||||
{ 0, NULL}
|
||||
};
|
||||
|
||||
static const NoteFuncDesc note_linux[] = {
|
||||
{sizeof(((Note *)0)->contents.prefix), s390x_write_elf64_prefix},
|
||||
{sizeof(((Note *)0)->contents.ctrs), s390x_write_elf64_ctrs},
|
||||
{sizeof(((Note *)0)->contents.timer), s390x_write_elf64_timer},
|
||||
{sizeof(((Note *)0)->contents.todcmp), s390x_write_elf64_todcmp},
|
||||
|
@ -178,25 +184,23 @@ static const struct NoteFuncDescStruct {
|
|||
{ 0, NULL}
|
||||
};
|
||||
|
||||
typedef struct NoteFuncDescStruct NoteFuncDesc;
|
||||
|
||||
|
||||
static int s390x_write_all_elf64_notes(const char *note_name,
|
||||
static int s390x_write_elf64_notes(const char *note_name,
|
||||
WriteCoreDumpFunction f,
|
||||
S390CPU *cpu, int id,
|
||||
void *opaque)
|
||||
void *opaque,
|
||||
const NoteFuncDesc *funcs)
|
||||
{
|
||||
Note note;
|
||||
const NoteFuncDesc *nf;
|
||||
int note_size;
|
||||
int ret = -1;
|
||||
|
||||
for (nf = note_func; nf->note_contents_func; nf++) {
|
||||
for (nf = funcs; nf->note_contents_func; nf++) {
|
||||
memset(¬e, 0, sizeof(note));
|
||||
note.hdr.n_namesz = cpu_to_be32(sizeof(note.name));
|
||||
note.hdr.n_namesz = cpu_to_be32(strlen(note_name) + 1);
|
||||
note.hdr.n_descsz = cpu_to_be32(nf->contents_size);
|
||||
strncpy(note.name, note_name, sizeof(note.name));
|
||||
(*nf->note_contents_func)(¬e, cpu);
|
||||
(*nf->note_contents_func)(¬e, cpu, id);
|
||||
|
||||
note_size = sizeof(note) - sizeof(note.contents) + nf->contents_size;
|
||||
ret = f(¬e, note_size, opaque);
|
||||
|
@ -215,7 +219,13 @@ int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
|
|||
int cpuid, void *opaque)
|
||||
{
|
||||
S390CPU *cpu = S390_CPU(cs);
|
||||
return s390x_write_all_elf64_notes("CORE", f, cpu, cpuid, opaque);
|
||||
int r;
|
||||
|
||||
r = s390x_write_elf64_notes("CORE", f, cpu, cpuid, opaque, note_core);
|
||||
if (r) {
|
||||
return r;
|
||||
}
|
||||
return s390x_write_elf64_notes("LINUX", f, cpu, cpuid, opaque, note_linux);
|
||||
}
|
||||
|
||||
int cpu_get_dump_info(ArchDumpInfo *info,
|
||||
|
@ -230,7 +240,7 @@ int cpu_get_dump_info(ArchDumpInfo *info,
|
|||
|
||||
ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
|
||||
{
|
||||
int name_size = 8; /* "CORE" or "QEMU" rounded */
|
||||
int name_size = 8; /* "LINUX" or "CORE" + pad */
|
||||
size_t elf_note_size = 0;
|
||||
int note_head_size;
|
||||
const NoteFuncDesc *nf;
|
||||
|
@ -240,7 +250,11 @@ ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
|
|||
|
||||
note_head_size = sizeof(Elf64_Nhdr);
|
||||
|
||||
for (nf = note_func; nf->note_contents_func; nf++) {
|
||||
for (nf = note_core; nf->note_contents_func; nf++) {
|
||||
elf_note_size = elf_note_size + note_head_size + name_size +
|
||||
nf->contents_size;
|
||||
}
|
||||
for (nf = note_linux; nf->note_contents_func; nf++) {
|
||||
elf_note_size = elf_note_size + note_head_size + name_size +
|
||||
nf->contents_size;
|
||||
}
|
||||
|
|
|
@ -1867,6 +1867,40 @@ static void unmanageable_intercept(S390CPU *cpu, const char *str, int pswoffset)
|
|||
qemu_system_guest_panicked(NULL);
|
||||
}
|
||||
|
||||
/* try to detect pgm check loops */
|
||||
static int handle_oper_loop(S390CPU *cpu, struct kvm_run *run)
|
||||
{
|
||||
CPUState *cs = CPU(cpu);
|
||||
PSW oldpsw, newpsw;
|
||||
|
||||
cpu_synchronize_state(cs);
|
||||
newpsw.mask = ldq_phys(cs->as, cpu->env.psa +
|
||||
offsetof(LowCore, program_new_psw));
|
||||
newpsw.addr = ldq_phys(cs->as, cpu->env.psa +
|
||||
offsetof(LowCore, program_new_psw) + 8);
|
||||
oldpsw.mask = run->psw_mask;
|
||||
oldpsw.addr = run->psw_addr;
|
||||
/*
|
||||
* Avoid endless loops of operation exceptions, if the pgm new
|
||||
* PSW will cause a new operation exception.
|
||||
* The heuristic checks if the pgm new psw is within 6 bytes before
|
||||
* the faulting psw address (with same DAT, AS settings) and the
|
||||
* new psw is not a wait psw and the fault was not triggered by
|
||||
* problem state. In that case go into crashed state.
|
||||
*/
|
||||
|
||||
if (oldpsw.addr - newpsw.addr <= 6 &&
|
||||
!(newpsw.mask & PSW_MASK_WAIT) &&
|
||||
!(oldpsw.mask & PSW_MASK_PSTATE) &&
|
||||
(newpsw.mask & PSW_MASK_ASC) == (oldpsw.mask & PSW_MASK_ASC) &&
|
||||
(newpsw.mask & PSW_MASK_DAT) == (oldpsw.mask & PSW_MASK_DAT)) {
|
||||
unmanageable_intercept(cpu, "operation exception loop",
|
||||
offsetof(LowCore, program_new_psw));
|
||||
return EXCP_HALTED;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_intercept(S390CPU *cpu)
|
||||
{
|
||||
CPUState *cs = CPU(cpu);
|
||||
|
@ -1914,11 +1948,14 @@ static int handle_intercept(S390CPU *cpu)
|
|||
r = EXCP_HALTED;
|
||||
break;
|
||||
case ICPT_OPEREXC:
|
||||
/* currently only instr 0x0000 after enabled via capability */
|
||||
/* check for break points */
|
||||
r = handle_sw_breakpoint(cpu, run);
|
||||
if (r == -ENOENT) {
|
||||
enter_pgmcheck(cpu, PGM_OPERATION);
|
||||
r = 0;
|
||||
/* Then check for potential pgm check loops */
|
||||
r = handle_oper_loop(cpu, run);
|
||||
if (r == 0) {
|
||||
enter_pgmcheck(cpu, PGM_OPERATION);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ICPT_SOFT_INTERCEPT:
|
||||
|
|
Loading…
Reference in New Issue