Several features, fixes and cleanups for kvm/s390:
- sclp event facility: cleanup structure. This allows to use realize/unrealize as well as migration support via vmsd - reboot: Two fixes that make reboot much more reliable - ipl: make elf loading more robust - flic interrupt controller: This allows to migrate floating interrupts, as well as clear them on reset etc. - enable async_pf feature of KVM on s390 - several sclp fixes and cleanups - several sigp fixes and cleanups -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJTDwZVAAoJEBF7vIC1phx8lx4P/Rv+UVD9XDFFF8yHuye1am40 NpRGjdarQ/9QUkS4gqyKwYUvIjAClk5id7U2d5zrfdc8XC49AH0ZhVFMdRupaOon AUqXjOXD5zAh9bfUcewg1EK1P1VuKcp0hyh0jFlIqk9Xmidw8N5guQ6iBoTqGJD5 UYTp0PuSqIjY1RCuF4fCTCurzRd1+J2oKcQBip7BSWlVuWZlg2/hPxoIraLezlz2 huwOU9tkSGXwSRv4C6fCcukEwlqnvkE6W0MCrHrcb2T8xYwAR2Jjs0TsscbKxb+t lIjZRiCxBrFwOLUqGN8DMYtZPffR+cigZ5bYb4o3PPJ0DQL4vLQVd8SPMPrdJhbb M7UOaeTclSTQuzmM/Uuc1pmrFc8PDq0dg50dT3weH2bW8aSgyqutYGpmUcm1Q6kq JLFuyswOBr1vS9o0TlBunP4+TqJJrnGvtIQ4EbRZm7zP78mBaIIrUcAZlbgOI+XI cSjtFXkBOCz0j28J9GSHrsWMC7RQ179TGdcH/FjDpu0dNDOxH7eH5gZPQoQDAqwC SjstqJdIFnd0qxOB1EqcgMUxbSqQYq3hoGvJ644ZrMA3T5trBn0fSw3J9ZU/qAK7 EvOKRacMfcacIj4l0aEQgpwqVmktwIYnkfetX/QAKw/4AImJz/R9GRkmYgjCfOH8 /CUfXM71zWLEdv1o5uJ5 =toIt -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/borntraeger/tags/kvm-s390-20140227' into staging Several features, fixes and cleanups for kvm/s390: - sclp event facility: cleanup structure. This allows to use realize/unrealize as well as migration support via vmsd - reboot: Two fixes that make reboot much more reliable - ipl: make elf loading more robust - flic interrupt controller: This allows to migrate floating interrupts, as well as clear them on reset etc. - enable async_pf feature of KVM on s390 - several sclp fixes and cleanups - several sigp fixes and cleanups * remotes/borntraeger/tags/kvm-s390-20140227: (22 commits) s390x/ipl: Fix crash of ELF images with arbitrary entry points s390x/kvm: Rework priv instruction handlers s390x/kvm: Add missing SIGP CPU RESET order s390x/kvm: Rework SIGP INITIAL CPU RESET handler s390x/cpu: Use ioctl to reset state in the kernel s390-ccw.img: new binary rom to match latest fixes s390-ccw.img: Fix sporadic errors with ccw boot image - initialize css s390-ccw.img: Fix sporadic reboot hangs: Initialize next_idx s390x/event-facility: exploit realize/unrealize s390x/event-facility: add support for live migration s390x/event-facility: code restructure s390x/event-facility: some renaming s390x/sclp: Fixed setting of condition code register s390x/sclp: Add missing checks to SCLP handler s390x/sclp: Fixed the size of sccb and code parameter s390x/eventfacility: mask out commands s390x/virtio-hcall: Specification exception for illegal subcodes s390x/virtio-hcall: Add range check for hypervisor call s390x/kvm: Fixed bad SIGP SET-ARCHITECTURE handler s390x/async_pf: Check for apf extension and enable pfault ... Conflicts: linux-headers/linux/kvm.h Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
		
						commit
						c2cb92f9ea
					
				| 
						 | 
					@ -1,2 +1,3 @@
 | 
				
			||||||
CONFIG_VIRTIO=y
 | 
					CONFIG_VIRTIO=y
 | 
				
			||||||
CONFIG_SCLPCONSOLE=y
 | 
					CONFIG_SCLPCONSOLE=y
 | 
				
			||||||
 | 
					CONFIG_S390_FLIC=$(CONFIG_KVM)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,3 +25,4 @@ obj-$(CONFIG_SH4) += sh_intc.o
 | 
				
			||||||
obj-$(CONFIG_XICS) += xics.o
 | 
					obj-$(CONFIG_XICS) += xics.o
 | 
				
			||||||
obj-$(CONFIG_XICS_KVM) += xics_kvm.o
 | 
					obj-$(CONFIG_XICS_KVM) += xics_kvm.o
 | 
				
			||||||
obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
 | 
					obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
 | 
				
			||||||
 | 
					obj-$(CONFIG_S390_FLIC) += s390_flic.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,322 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * QEMU S390x KVM floating interrupt controller (flic)
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright 2014 IBM Corp.
 | 
				
			||||||
 | 
					 * Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This work is licensed under the terms of the GNU GPL, version 2 or (at
 | 
				
			||||||
 | 
					 * your option) any later version. See the COPYING file in the top-level
 | 
				
			||||||
 | 
					 * directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <sys/ioctl.h>
 | 
				
			||||||
 | 
					#include "qemu/error-report.h"
 | 
				
			||||||
 | 
					#include "hw/sysbus.h"
 | 
				
			||||||
 | 
					#include "sysemu/kvm.h"
 | 
				
			||||||
 | 
					#include "migration/qemu-file.h"
 | 
				
			||||||
 | 
					#include "hw/s390x/s390_flic.h"
 | 
				
			||||||
 | 
					#include "trace.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define FLIC_SAVE_INITIAL_SIZE getpagesize()
 | 
				
			||||||
 | 
					#define FLIC_FAILED (-1UL)
 | 
				
			||||||
 | 
					#define FLIC_SAVEVM_VERSION 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void s390_flic_init(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    DeviceState *dev;
 | 
				
			||||||
 | 
					    int r;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (kvm_enabled()) {
 | 
				
			||||||
 | 
					        dev = qdev_create(NULL, "s390-flic");
 | 
				
			||||||
 | 
					        object_property_add_child(qdev_get_machine(), "s390-flic",
 | 
				
			||||||
 | 
					                                OBJECT(dev), NULL);
 | 
				
			||||||
 | 
					        r = qdev_init(dev);
 | 
				
			||||||
 | 
					        if (r) {
 | 
				
			||||||
 | 
					            error_report("flic: couldn't create qdev");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * flic_get_all_irqs - store all pending irqs in buffer
 | 
				
			||||||
 | 
					 * @buf: pointer to buffer which is passed to kernel
 | 
				
			||||||
 | 
					 * @len: length of buffer
 | 
				
			||||||
 | 
					 * @flic: pointer to flic device state
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns: -ENOMEM if buffer is too small,
 | 
				
			||||||
 | 
					 * -EINVAL if attr.group is invalid,
 | 
				
			||||||
 | 
					 * -EFAULT if copying to userspace failed,
 | 
				
			||||||
 | 
					 * on success return number of stored interrupts
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int flic_get_all_irqs(KVMS390FLICState *flic,
 | 
				
			||||||
 | 
					                             void *buf, int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct kvm_device_attr attr = {
 | 
				
			||||||
 | 
					        .group = KVM_DEV_FLIC_GET_ALL_IRQS,
 | 
				
			||||||
 | 
					        .addr = (uint64_t) buf,
 | 
				
			||||||
 | 
					        .attr = len,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rc = ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return rc == -1 ? -errno : rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void flic_enable_pfault(KVMS390FLICState *flic)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct kvm_device_attr attr = {
 | 
				
			||||||
 | 
					        .group = KVM_DEV_FLIC_APF_ENABLE,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (rc) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "flic: couldn't enable pfault\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void flic_disable_wait_pfault(KVMS390FLICState *flic)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct kvm_device_attr attr = {
 | 
				
			||||||
 | 
					        .group = KVM_DEV_FLIC_APF_DISABLE_WAIT,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (rc) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "flic: couldn't disable pfault\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** flic_enqueue_irqs - returns 0 on success
 | 
				
			||||||
 | 
					 * @buf: pointer to buffer which is passed to kernel
 | 
				
			||||||
 | 
					 * @len: length of buffer
 | 
				
			||||||
 | 
					 * @flic: pointer to flic device state
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns: -EINVAL if attr.group is unknown
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int flic_enqueue_irqs(void *buf, uint64_t len,
 | 
				
			||||||
 | 
					                            KVMS390FLICState *flic)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int rc;
 | 
				
			||||||
 | 
					    struct kvm_device_attr attr = {
 | 
				
			||||||
 | 
					        .group = KVM_DEV_FLIC_ENQUEUE,
 | 
				
			||||||
 | 
					        .addr = (uint64_t) buf,
 | 
				
			||||||
 | 
					        .attr = len,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return rc ? -errno : 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * __get_all_irqs - store all pending irqs in buffer
 | 
				
			||||||
 | 
					 * @flic: pointer to flic device state
 | 
				
			||||||
 | 
					 * @buf: pointer to pointer to a buffer
 | 
				
			||||||
 | 
					 * @len: length of buffer
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns: return value of flic_get_all_irqs
 | 
				
			||||||
 | 
					 * Note: Retry and increase buffer size until flic_get_all_irqs
 | 
				
			||||||
 | 
					 * either returns a value >= 0 or a negative error code.
 | 
				
			||||||
 | 
					 * -ENOMEM is an exception, which means the buffer is too small
 | 
				
			||||||
 | 
					 * and we should try again. Other negative error codes can be
 | 
				
			||||||
 | 
					 * -EFAULT and -EINVAL which we ignore at this point
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int __get_all_irqs(KVMS390FLICState *flic,
 | 
				
			||||||
 | 
					                          void **buf, int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int r;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    do {
 | 
				
			||||||
 | 
					        /* returns -ENOMEM if buffer is too small and number
 | 
				
			||||||
 | 
					         * of queued interrupts on success */
 | 
				
			||||||
 | 
					        r = flic_get_all_irqs(flic, *buf, len);
 | 
				
			||||||
 | 
					        if (r >= 0) {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        len *= 2;
 | 
				
			||||||
 | 
					        *buf = g_try_realloc(*buf, len);
 | 
				
			||||||
 | 
					        if (!buf) {
 | 
				
			||||||
 | 
					            return -ENOMEM;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } while (r == -ENOMEM && len <= KVM_S390_FLIC_MAX_BUFFER);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return r;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * kvm_flic_save - Save pending floating interrupts
 | 
				
			||||||
 | 
					 * @f: QEMUFile containing migration state
 | 
				
			||||||
 | 
					 * @opaque: pointer to flic device state
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Note: Pass buf and len to kernel. Start with one page and
 | 
				
			||||||
 | 
					 * increase until buffer is sufficient or maxium size is
 | 
				
			||||||
 | 
					 * reached
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void kvm_flic_save(QEMUFile *f, void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    KVMS390FLICState *flic = opaque;
 | 
				
			||||||
 | 
					    int len = FLIC_SAVE_INITIAL_SIZE;
 | 
				
			||||||
 | 
					    void *buf;
 | 
				
			||||||
 | 
					    int count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    flic_disable_wait_pfault((struct KVMS390FLICState *) opaque);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    buf = g_try_malloc0(len);
 | 
				
			||||||
 | 
					    if (!buf) {
 | 
				
			||||||
 | 
					        /* Storing FLIC_FAILED into the count field here will cause the
 | 
				
			||||||
 | 
					         * target system to fail when attempting to load irqs from the
 | 
				
			||||||
 | 
					         * migration state */
 | 
				
			||||||
 | 
					        error_report("flic: couldn't allocate memory");
 | 
				
			||||||
 | 
					        qemu_put_be64(f, FLIC_FAILED);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    count = __get_all_irqs(flic, &buf, len);
 | 
				
			||||||
 | 
					    if (count < 0) {
 | 
				
			||||||
 | 
					        error_report("flic: couldn't retrieve irqs from kernel, rc %d",
 | 
				
			||||||
 | 
					                     count);
 | 
				
			||||||
 | 
					        /* Storing FLIC_FAILED into the count field here will cause the
 | 
				
			||||||
 | 
					         * target system to fail when attempting to load irqs from the
 | 
				
			||||||
 | 
					         * migration state */
 | 
				
			||||||
 | 
					        qemu_put_be64(f, FLIC_FAILED);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        qemu_put_be64(f, count);
 | 
				
			||||||
 | 
					        qemu_put_buffer(f, (uint8_t *) buf,
 | 
				
			||||||
 | 
					                        count * sizeof(struct kvm_s390_irq));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    g_free(buf);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * kvm_flic_load - Load pending floating interrupts
 | 
				
			||||||
 | 
					 * @f: QEMUFile containing migration state
 | 
				
			||||||
 | 
					 * @opaque: pointer to flic device state
 | 
				
			||||||
 | 
					 * @version_id: version id for migration
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns: value of flic_enqueue_irqs, -EINVAL on error
 | 
				
			||||||
 | 
					 * Note: Do nothing when no interrupts where stored
 | 
				
			||||||
 | 
					 * in QEMUFile
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int kvm_flic_load(QEMUFile *f, void *opaque, int version_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint64_t len = 0;
 | 
				
			||||||
 | 
					    uint64_t count = 0;
 | 
				
			||||||
 | 
					    void *buf = NULL;
 | 
				
			||||||
 | 
					    int r = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (version_id != FLIC_SAVEVM_VERSION) {
 | 
				
			||||||
 | 
					        r = -EINVAL;
 | 
				
			||||||
 | 
					        goto out;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    flic_enable_pfault((struct KVMS390FLICState *) opaque);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    count = qemu_get_be64(f);
 | 
				
			||||||
 | 
					    len = count * sizeof(struct kvm_s390_irq);
 | 
				
			||||||
 | 
					    if (count == FLIC_FAILED) {
 | 
				
			||||||
 | 
					        r = -EINVAL;
 | 
				
			||||||
 | 
					        goto out;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (count == 0) {
 | 
				
			||||||
 | 
					        r = 0;
 | 
				
			||||||
 | 
					        goto out;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    buf = g_try_malloc0(len);
 | 
				
			||||||
 | 
					    if (!buf) {
 | 
				
			||||||
 | 
					        r = -ENOMEM;
 | 
				
			||||||
 | 
					        goto out;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) {
 | 
				
			||||||
 | 
					        r = -EINVAL;
 | 
				
			||||||
 | 
					        goto out_free;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out_free:
 | 
				
			||||||
 | 
					    g_free(buf);
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
					    return r;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
 | 
				
			||||||
 | 
					    struct kvm_create_device cd = {0};
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    flic_state->fd = -1;
 | 
				
			||||||
 | 
					    if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) {
 | 
				
			||||||
 | 
					        trace_flic_no_device_api(errno);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cd.type = KVM_DEV_TYPE_FLIC;
 | 
				
			||||||
 | 
					    ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
 | 
				
			||||||
 | 
					    if (ret < 0) {
 | 
				
			||||||
 | 
					        trace_flic_create_device(errno);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    flic_state->fd = cd.fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Register savevm handler for floating interrupts */
 | 
				
			||||||
 | 
					    register_savevm(NULL, "s390-flic", 0, 1, kvm_flic_save,
 | 
				
			||||||
 | 
					                    kvm_flic_load, (void *) flic_state);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void kvm_s390_flic_unrealize(DeviceState *dev, Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unregister_savevm(DEVICE(flic_state), "s390-flic", flic_state);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void kvm_s390_flic_reset(DeviceState *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    KVMS390FLICState *flic = KVM_S390_FLIC(dev);
 | 
				
			||||||
 | 
					    struct kvm_device_attr attr = {
 | 
				
			||||||
 | 
					        .group = KVM_DEV_FLIC_CLEAR_IRQS,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    int rc = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (flic->fd == -1) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    flic_disable_wait_pfault(flic);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
 | 
				
			||||||
 | 
					    if (rc) {
 | 
				
			||||||
 | 
					        trace_flic_reset_failed(errno);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    flic_enable_pfault(flic);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    DeviceClass *dc = DEVICE_CLASS(oc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dc->realize = kvm_s390_flic_realize;
 | 
				
			||||||
 | 
					    dc->unrealize = kvm_s390_flic_unrealize;
 | 
				
			||||||
 | 
					    dc->reset = kvm_s390_flic_reset;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const TypeInfo kvm_s390_flic_info = {
 | 
				
			||||||
 | 
					    .name          = TYPE_KVM_S390_FLIC,
 | 
				
			||||||
 | 
					    .parent        = TYPE_SYS_BUS_DEVICE,
 | 
				
			||||||
 | 
					    .instance_size = sizeof(KVMS390FLICState),
 | 
				
			||||||
 | 
					    .class_init    = kvm_s390_flic_class_init,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void kvm_s390_flic_register_types(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    type_register_static(&kvm_s390_flic_info);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type_init(kvm_s390_flic_register_types)
 | 
				
			||||||
| 
						 | 
					@ -21,13 +21,13 @@
 | 
				
			||||||
#include "hw/s390x/sclp.h"
 | 
					#include "hw/s390x/sclp.h"
 | 
				
			||||||
#include "hw/s390x/event-facility.h"
 | 
					#include "hw/s390x/event-facility.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct EventTypesBus {
 | 
					typedef struct SCLPEventsBus {
 | 
				
			||||||
    BusState qbus;
 | 
					    BusState qbus;
 | 
				
			||||||
} EventTypesBus;
 | 
					} SCLPEventsBus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct SCLPEventFacility {
 | 
					struct SCLPEventFacility {
 | 
				
			||||||
    EventTypesBus sbus;
 | 
					    SysBusDevice parent_obj;
 | 
				
			||||||
    DeviceState *qdev;
 | 
					    SCLPEventsBus sbus;
 | 
				
			||||||
    /* guest' receive mask */
 | 
					    /* guest' receive mask */
 | 
				
			||||||
    unsigned int receive_mask;
 | 
					    unsigned int receive_mask;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -291,7 +291,7 @@ static void sclp_events_bus_class_init(ObjectClass *klass, void *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const TypeInfo s390_sclp_events_bus_info = {
 | 
					static const TypeInfo sclp_events_bus_info = {
 | 
				
			||||||
    .name = TYPE_SCLP_EVENTS_BUS,
 | 
					    .name = TYPE_SCLP_EVENTS_BUS,
 | 
				
			||||||
    .parent = TYPE_BUS,
 | 
					    .parent = TYPE_BUS,
 | 
				
			||||||
    .class_init = sclp_events_bus_class_init,
 | 
					    .class_init = sclp_events_bus_class_init,
 | 
				
			||||||
| 
						 | 
					@ -299,7 +299,7 @@ static const TypeInfo s390_sclp_events_bus_info = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code)
 | 
					static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    switch (code) {
 | 
					    switch (code & SCLP_CMD_CODE_MASK) {
 | 
				
			||||||
    case SCLP_CMD_READ_EVENT_DATA:
 | 
					    case SCLP_CMD_READ_EVENT_DATA:
 | 
				
			||||||
        read_event_data(ef, sccb);
 | 
					        read_event_data(ef, sccb);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
| 
						 | 
					@ -315,21 +315,26 @@ static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int init_event_facility(S390SCLPDevice *sdev)
 | 
					static const VMStateDescription vmstate_event_facility = {
 | 
				
			||||||
 | 
					    .name = "vmstate-event-facility",
 | 
				
			||||||
 | 
					    .version_id = 0,
 | 
				
			||||||
 | 
					    .minimum_version_id = 0,
 | 
				
			||||||
 | 
					    .minimum_version_id_old = 0,
 | 
				
			||||||
 | 
					    .fields      = (VMStateField[]) {
 | 
				
			||||||
 | 
					        VMSTATE_UINT32(receive_mask, SCLPEventFacility),
 | 
				
			||||||
 | 
					        VMSTATE_END_OF_LIST()
 | 
				
			||||||
 | 
					     }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int init_event_facility(SCLPEventFacility *event_facility)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    SCLPEventFacility *event_facility;
 | 
					    DeviceState *sdev = DEVICE(event_facility);
 | 
				
			||||||
    DeviceState *quiesce;
 | 
					    DeviceState *quiesce;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    event_facility = g_malloc0(sizeof(SCLPEventFacility));
 | 
					    /* Spawn a new bus for SCLP events */
 | 
				
			||||||
    sdev->ef = event_facility;
 | 
					 | 
				
			||||||
    sdev->sclp_command_handler = command_handler;
 | 
					 | 
				
			||||||
    sdev->event_pending = event_pending;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Spawn a new sclp-events facility */
 | 
					 | 
				
			||||||
    qbus_create_inplace(&event_facility->sbus, sizeof(event_facility->sbus),
 | 
					    qbus_create_inplace(&event_facility->sbus, sizeof(event_facility->sbus),
 | 
				
			||||||
                        TYPE_SCLP_EVENTS_BUS, DEVICE(sdev), NULL);
 | 
					                        TYPE_SCLP_EVENTS_BUS, sdev, NULL);
 | 
				
			||||||
    event_facility->sbus.qbus.allow_hotplug = 0;
 | 
					    event_facility->sbus.qbus.allow_hotplug = 0;
 | 
				
			||||||
    event_facility->qdev = (DeviceState *) sdev;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    quiesce = qdev_create(&event_facility->sbus.qbus, "sclpquiesce");
 | 
					    quiesce = qdev_create(&event_facility->sbus.qbus, "sclpquiesce");
 | 
				
			||||||
    if (!quiesce) {
 | 
					    if (!quiesce) {
 | 
				
			||||||
| 
						 | 
					@ -346,43 +351,57 @@ static int init_event_facility(S390SCLPDevice *sdev)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void reset_event_facility(DeviceState *dev)
 | 
					static void reset_event_facility(DeviceState *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    S390SCLPDevice *sdev = SCLP_S390_DEVICE(dev);
 | 
					    SCLPEventFacility *sdev = EVENT_FACILITY(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sdev->ef->receive_mask = 0;
 | 
					    sdev->receive_mask = 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void init_event_facility_class(ObjectClass *klass, void *data)
 | 
					static void init_event_facility_class(ObjectClass *klass, void *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    DeviceClass *dc = DEVICE_CLASS(klass);
 | 
					    SysBusDeviceClass *sbdc = SYS_BUS_DEVICE_CLASS(klass);
 | 
				
			||||||
    S390SCLPDeviceClass *k = SCLP_S390_DEVICE_CLASS(klass);
 | 
					    DeviceClass *dc = DEVICE_CLASS(sbdc);
 | 
				
			||||||
 | 
					    SCLPEventFacilityClass *k = EVENT_FACILITY_CLASS(dc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    dc->reset = reset_event_facility;
 | 
					    dc->reset = reset_event_facility;
 | 
				
			||||||
 | 
					    dc->vmsd = &vmstate_event_facility;
 | 
				
			||||||
    k->init = init_event_facility;
 | 
					    k->init = init_event_facility;
 | 
				
			||||||
 | 
					    k->command_handler = command_handler;
 | 
				
			||||||
 | 
					    k->event_pending = event_pending;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const TypeInfo s390_sclp_event_facility_info = {
 | 
					static const TypeInfo sclp_event_facility_info = {
 | 
				
			||||||
    .name          = "s390-sclp-event-facility",
 | 
					    .name          = TYPE_SCLP_EVENT_FACILITY,
 | 
				
			||||||
    .parent        = TYPE_DEVICE_S390_SCLP,
 | 
					    .parent        = TYPE_SYS_BUS_DEVICE,
 | 
				
			||||||
    .instance_size = sizeof(S390SCLPDevice),
 | 
					    .instance_size = sizeof(SCLPEventFacility),
 | 
				
			||||||
    .class_init    = init_event_facility_class,
 | 
					    .class_init    = init_event_facility_class,
 | 
				
			||||||
 | 
					    .class_size    = sizeof(SCLPEventFacilityClass),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int event_qdev_init(DeviceState *qdev)
 | 
					static void event_realize(DeviceState *qdev, Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    SCLPEvent *event = DO_UPCAST(SCLPEvent, qdev, qdev);
 | 
					    SCLPEvent *event = SCLP_EVENT(qdev);
 | 
				
			||||||
    SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event);
 | 
					    SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return child->init(event);
 | 
					    if (child->init) {
 | 
				
			||||||
 | 
					        int rc = child->init(event);
 | 
				
			||||||
 | 
					        if (rc < 0) {
 | 
				
			||||||
 | 
					            error_setg(errp, "SCLP event initialization failed.");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int event_qdev_exit(DeviceState *qdev)
 | 
					static void event_unrealize(DeviceState *qdev, Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    SCLPEvent *event = DO_UPCAST(SCLPEvent, qdev, qdev);
 | 
					    SCLPEvent *event = SCLP_EVENT(qdev);
 | 
				
			||||||
    SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event);
 | 
					    SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event);
 | 
				
			||||||
    if (child->exit) {
 | 
					    if (child->exit) {
 | 
				
			||||||
        child->exit(event);
 | 
					        int rc = child->exit(event);
 | 
				
			||||||
 | 
					        if (rc < 0) {
 | 
				
			||||||
 | 
					            error_setg(errp, "SCLP event exit failed.");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void event_class_init(ObjectClass *klass, void *data)
 | 
					static void event_class_init(ObjectClass *klass, void *data)
 | 
				
			||||||
| 
						 | 
					@ -391,11 +410,11 @@ static void event_class_init(ObjectClass *klass, void *data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    dc->bus_type = TYPE_SCLP_EVENTS_BUS;
 | 
					    dc->bus_type = TYPE_SCLP_EVENTS_BUS;
 | 
				
			||||||
    dc->unplug = qdev_simple_unplug_cb;
 | 
					    dc->unplug = qdev_simple_unplug_cb;
 | 
				
			||||||
    dc->init = event_qdev_init;
 | 
					    dc->realize = event_realize;
 | 
				
			||||||
    dc->exit = event_qdev_exit;
 | 
					    dc->unrealize = event_unrealize;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const TypeInfo s390_sclp_event_type_info = {
 | 
					static const TypeInfo sclp_event_type_info = {
 | 
				
			||||||
    .name = TYPE_SCLP_EVENT,
 | 
					    .name = TYPE_SCLP_EVENT,
 | 
				
			||||||
    .parent = TYPE_DEVICE,
 | 
					    .parent = TYPE_DEVICE,
 | 
				
			||||||
    .instance_size = sizeof(SCLPEvent),
 | 
					    .instance_size = sizeof(SCLPEvent),
 | 
				
			||||||
| 
						 | 
					@ -406,9 +425,9 @@ static const TypeInfo s390_sclp_event_type_info = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void register_types(void)
 | 
					static void register_types(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    type_register_static(&s390_sclp_events_bus_info);
 | 
					    type_register_static(&sclp_events_bus_info);
 | 
				
			||||||
    type_register_static(&s390_sclp_event_facility_info);
 | 
					    type_register_static(&sclp_event_facility_info);
 | 
				
			||||||
    type_register_static(&s390_sclp_event_type_info);
 | 
					    type_register_static(&sclp_event_type_info);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type_init(register_types)
 | 
					type_init(register_types)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -95,7 +95,8 @@ static int s390_ipl_init(SysBusDevice *dev)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        kernel_size = load_elf(ipl->kernel, NULL, NULL, NULL, NULL,
 | 
					        uint64_t pentry = KERN_IMAGE_START;
 | 
				
			||||||
 | 
					        kernel_size = load_elf(ipl->kernel, NULL, NULL, &pentry, NULL,
 | 
				
			||||||
                               NULL, 1, ELF_MACHINE, 0);
 | 
					                               NULL, 1, ELF_MACHINE, 0);
 | 
				
			||||||
        if (kernel_size == -1) {
 | 
					        if (kernel_size == -1) {
 | 
				
			||||||
            kernel_size = load_image_targphys(ipl->kernel, 0, ram_size);
 | 
					            kernel_size = load_image_targphys(ipl->kernel, 0, ram_size);
 | 
				
			||||||
| 
						 | 
					@ -104,15 +105,19 @@ static int s390_ipl_init(SysBusDevice *dev)
 | 
				
			||||||
            fprintf(stderr, "could not load kernel '%s'\n", ipl->kernel);
 | 
					            fprintf(stderr, "could not load kernel '%s'\n", ipl->kernel);
 | 
				
			||||||
            return -1;
 | 
					            return -1;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        /* we have to overwrite values in the kernel image, which are "rom" */
 | 
					 | 
				
			||||||
        strcpy(rom_ptr(KERN_PARM_AREA), ipl->cmdline);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /*
 | 
					        /*
 | 
				
			||||||
         * we can not rely on the ELF entry point, since up to 3.2 this
 | 
					         * Is it a Linux kernel (starting at 0x10000)? If yes, we fill in the
 | 
				
			||||||
         * value was 0x800 (the SALIPL loader) and it wont work. For
 | 
					         * kernel parameters here as well. Note: For old kernels (up to 3.2)
 | 
				
			||||||
         * all (Linux) cases 0x10000 (KERN_IMAGE_START) should be fine.
 | 
					         * we can not rely on the ELF entry point - it was 0x800 (the SALIPL
 | 
				
			||||||
 | 
					         * loader) and it won't work. For this case we force it to 0x10000, too.
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
        ipl->start_addr = KERN_IMAGE_START;
 | 
					        if (pentry == KERN_IMAGE_START || pentry == 0x800) {
 | 
				
			||||||
 | 
					            ipl->start_addr = KERN_IMAGE_START;
 | 
				
			||||||
 | 
					            /* Overwrite parameters in the kernel image, which are "rom" */
 | 
				
			||||||
 | 
					            strcpy(rom_ptr(KERN_PARM_AREA), ipl->cmdline);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            ipl->start_addr = pentry;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (ipl->initrd) {
 | 
					    if (ipl->initrd) {
 | 
				
			||||||
        ram_addr_t initrd_offset;
 | 
					        ram_addr_t initrd_offset;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,13 +13,14 @@
 | 
				
			||||||
#include "exec/address-spaces.h"
 | 
					#include "exec/address-spaces.h"
 | 
				
			||||||
#include "s390-virtio.h"
 | 
					#include "s390-virtio.h"
 | 
				
			||||||
#include "hw/s390x/sclp.h"
 | 
					#include "hw/s390x/sclp.h"
 | 
				
			||||||
 | 
					#include "hw/s390x/s390_flic.h"
 | 
				
			||||||
#include "ioinst.h"
 | 
					#include "ioinst.h"
 | 
				
			||||||
#include "css.h"
 | 
					#include "css.h"
 | 
				
			||||||
#include "virtio-ccw.h"
 | 
					#include "virtio-ccw.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void io_subsystem_reset(void)
 | 
					void io_subsystem_reset(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    DeviceState *css, *sclp;
 | 
					    DeviceState *css, *sclp, *flic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    css = DEVICE(object_resolve_path_type("", "virtual-css-bridge", NULL));
 | 
					    css = DEVICE(object_resolve_path_type("", "virtual-css-bridge", NULL));
 | 
				
			||||||
    if (css) {
 | 
					    if (css) {
 | 
				
			||||||
| 
						 | 
					@ -30,6 +31,10 @@ void io_subsystem_reset(void)
 | 
				
			||||||
    if (sclp) {
 | 
					    if (sclp) {
 | 
				
			||||||
        qdev_reset_all(sclp);
 | 
					        qdev_reset_all(sclp);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    flic = DEVICE(object_resolve_path_type("", "s390-flic", NULL));
 | 
				
			||||||
 | 
					    if (flic) {
 | 
				
			||||||
 | 
					        qdev_reset_all(flic);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int virtio_ccw_hcall_notify(const uint64_t *args)
 | 
					static int virtio_ccw_hcall_notify(const uint64_t *args)
 | 
				
			||||||
| 
						 | 
					@ -99,6 +104,7 @@ static void ccw_init(QEMUMachineInitArgs *args)
 | 
				
			||||||
    s390_sclp_init();
 | 
					    s390_sclp_init();
 | 
				
			||||||
    s390_init_ipl_dev(args->kernel_filename, args->kernel_cmdline,
 | 
					    s390_init_ipl_dev(args->kernel_filename, args->kernel_cmdline,
 | 
				
			||||||
                      args->initrd_filename, "s390-ccw.img");
 | 
					                      args->initrd_filename, "s390-ccw.img");
 | 
				
			||||||
 | 
					    s390_flic_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* register hypercalls */
 | 
					    /* register hypercalls */
 | 
				
			||||||
    virtio_ccw_register_hcalls();
 | 
					    virtio_ccw_register_hcalls();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,11 +26,15 @@ void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int s390_virtio_hypercall(CPUS390XState *env)
 | 
					int s390_virtio_hypercall(CPUS390XState *env)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    s390_virtio_fn fn = s390_diag500_table[env->regs[1]];
 | 
					    s390_virtio_fn fn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!fn) {
 | 
					    if (env->regs[1] < MAX_DIAG_SUBCODES) {
 | 
				
			||||||
        return -EINVAL;
 | 
					        fn = s390_diag500_table[env->regs[1]];
 | 
				
			||||||
 | 
					        if (fn) {
 | 
				
			||||||
 | 
					            env->regs[2] = fn(&env->regs[2]);
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return fn(&env->regs[2]);
 | 
					    return -EINVAL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,6 +36,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "hw/s390x/s390-virtio-bus.h"
 | 
					#include "hw/s390x/s390-virtio-bus.h"
 | 
				
			||||||
#include "hw/s390x/sclp.h"
 | 
					#include "hw/s390x/sclp.h"
 | 
				
			||||||
 | 
					#include "hw/s390x/s390_flic.h"
 | 
				
			||||||
#include "hw/s390x/s390-virtio.h"
 | 
					#include "hw/s390x/s390-virtio.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//#define DEBUG_S390
 | 
					//#define DEBUG_S390
 | 
				
			||||||
| 
						 | 
					@ -251,6 +252,7 @@ static void s390_init(QEMUMachineInitArgs *args)
 | 
				
			||||||
    s390_sclp_init();
 | 
					    s390_sclp_init();
 | 
				
			||||||
    s390_init_ipl_dev(args->kernel_filename, args->kernel_cmdline,
 | 
					    s390_init_ipl_dev(args->kernel_filename, args->kernel_cmdline,
 | 
				
			||||||
                      args->initrd_filename, ZIPL_FILENAME);
 | 
					                      args->initrd_filename, ZIPL_FILENAME);
 | 
				
			||||||
 | 
					    s390_flic_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* register hypercalls */
 | 
					    /* register hypercalls */
 | 
				
			||||||
    s390_virtio_register_hcalls();
 | 
					    s390_virtio_register_hcalls();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,11 +18,12 @@
 | 
				
			||||||
#include "sysemu/sysemu.h"
 | 
					#include "sysemu/sysemu.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "hw/s390x/sclp.h"
 | 
					#include "hw/s390x/sclp.h"
 | 
				
			||||||
 | 
					#include "hw/s390x/event-facility.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline S390SCLPDevice *get_event_facility(void)
 | 
					static inline SCLPEventFacility *get_event_facility(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    ObjectProperty *op = object_property_find(qdev_get_machine(),
 | 
					    ObjectProperty *op = object_property_find(qdev_get_machine(),
 | 
				
			||||||
                                              "s390-sclp-event-facility",
 | 
					                                              TYPE_SCLP_EVENT_FACILITY,
 | 
				
			||||||
                                              NULL);
 | 
					                                              NULL);
 | 
				
			||||||
    assert(op);
 | 
					    assert(op);
 | 
				
			||||||
    return op->opaque;
 | 
					    return op->opaque;
 | 
				
			||||||
| 
						 | 
					@ -89,9 +90,10 @@ static void sclp_read_cpu_info(SCCB *sccb)
 | 
				
			||||||
    sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
 | 
					    sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void sclp_execute(SCCB *sccb, uint64_t code)
 | 
					static void sclp_execute(SCCB *sccb, uint32_t code)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    S390SCLPDevice *sdev = get_event_facility();
 | 
					    SCLPEventFacility *ef = get_event_facility();
 | 
				
			||||||
 | 
					    SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    switch (code & SCLP_CMD_CODE_MASK) {
 | 
					    switch (code & SCLP_CMD_CODE_MASK) {
 | 
				
			||||||
    case SCLP_CMDW_READ_SCP_INFO:
 | 
					    case SCLP_CMDW_READ_SCP_INFO:
 | 
				
			||||||
| 
						 | 
					@ -102,12 +104,12 @@ static void sclp_execute(SCCB *sccb, uint64_t code)
 | 
				
			||||||
        sclp_read_cpu_info(sccb);
 | 
					        sclp_read_cpu_info(sccb);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
        sdev->sclp_command_handler(sdev->ef, sccb, code);
 | 
					        efc->command_handler(ef, sccb, code);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int sclp_service_call(uint32_t sccb, uint64_t code)
 | 
					int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int r = 0;
 | 
					    int r = 0;
 | 
				
			||||||
    SCCB work_sccb;
 | 
					    SCCB work_sccb;
 | 
				
			||||||
| 
						 | 
					@ -115,11 +117,16 @@ int sclp_service_call(uint32_t sccb, uint64_t code)
 | 
				
			||||||
    hwaddr sccb_len = sizeof(SCCB);
 | 
					    hwaddr sccb_len = sizeof(SCCB);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* first some basic checks on program checks */
 | 
					    /* first some basic checks on program checks */
 | 
				
			||||||
 | 
					    if (env->psw.mask & PSW_MASK_PSTATE) {
 | 
				
			||||||
 | 
					        r = -PGM_PRIVILEGED;
 | 
				
			||||||
 | 
					        goto out;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    if (cpu_physical_memory_is_io(sccb)) {
 | 
					    if (cpu_physical_memory_is_io(sccb)) {
 | 
				
			||||||
        r = -PGM_ADDRESSING;
 | 
					        r = -PGM_ADDRESSING;
 | 
				
			||||||
        goto out;
 | 
					        goto out;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (sccb & ~0x7ffffff8ul) {
 | 
					    if ((sccb & ~0x1fffUL) == 0 || (sccb & ~0x1fffUL) == env->psa
 | 
				
			||||||
 | 
					        || (sccb & ~0x7ffffff8UL) != 0) {
 | 
				
			||||||
        r = -PGM_SPECIFICATION;
 | 
					        r = -PGM_SPECIFICATION;
 | 
				
			||||||
        goto out;
 | 
					        goto out;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -151,11 +158,13 @@ out:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void sclp_service_interrupt(uint32_t sccb)
 | 
					void sclp_service_interrupt(uint32_t sccb)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    S390SCLPDevice *sdev = get_event_facility();
 | 
					    SCLPEventFacility *ef = get_event_facility();
 | 
				
			||||||
 | 
					    SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint32_t param = sccb & ~3;
 | 
					    uint32_t param = sccb & ~3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Indicate whether an event is still pending */
 | 
					    /* Indicate whether an event is still pending */
 | 
				
			||||||
    param |= sdev->event_pending(sdev->ef) ? 1 : 0;
 | 
					    param |= efc->event_pending(ef) ? 1 : 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!param) {
 | 
					    if (!param) {
 | 
				
			||||||
        /* No need to send an interrupt, there's nothing to be notified about */
 | 
					        /* No need to send an interrupt, there's nothing to be notified about */
 | 
				
			||||||
| 
						 | 
					@ -168,47 +177,9 @@ void sclp_service_interrupt(uint32_t sccb)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void s390_sclp_init(void)
 | 
					void s390_sclp_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    DeviceState *dev  = qdev_create(NULL, "s390-sclp-event-facility");
 | 
					    DeviceState *dev  = qdev_create(NULL, TYPE_SCLP_EVENT_FACILITY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    object_property_add_child(qdev_get_machine(), "s390-sclp-event-facility",
 | 
					    object_property_add_child(qdev_get_machine(), TYPE_SCLP_EVENT_FACILITY,
 | 
				
			||||||
                              OBJECT(dev), NULL);
 | 
					                              OBJECT(dev), NULL);
 | 
				
			||||||
    qdev_init_nofail(dev);
 | 
					    qdev_init_nofail(dev);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
static int s390_sclp_dev_init(SysBusDevice *dev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int r;
 | 
					 | 
				
			||||||
    S390SCLPDevice *sdev = (S390SCLPDevice *)dev;
 | 
					 | 
				
			||||||
    S390SCLPDeviceClass *sclp = SCLP_S390_DEVICE_GET_CLASS(dev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    r = sclp->init(sdev);
 | 
					 | 
				
			||||||
    if (!r) {
 | 
					 | 
				
			||||||
        assert(sdev->event_pending);
 | 
					 | 
				
			||||||
        assert(sdev->sclp_command_handler);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return r;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void s390_sclp_device_class_init(ObjectClass *klass, void *data)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    SysBusDeviceClass *dc = SYS_BUS_DEVICE_CLASS(klass);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    dc->init = s390_sclp_dev_init;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const TypeInfo s390_sclp_device_info = {
 | 
					 | 
				
			||||||
    .name = TYPE_DEVICE_S390_SCLP,
 | 
					 | 
				
			||||||
    .parent = TYPE_SYS_BUS_DEVICE,
 | 
					 | 
				
			||||||
    .instance_size = sizeof(S390SCLPDevice),
 | 
					 | 
				
			||||||
    .class_init = s390_sclp_device_class_init,
 | 
					 | 
				
			||||||
    .class_size = sizeof(S390SCLPDeviceClass),
 | 
					 | 
				
			||||||
    .abstract = true,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void s390_sclp_register_types(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    type_register_static(&s390_sclp_device_info);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type_init(s390_sclp_register_types)
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -176,4 +176,23 @@ typedef struct SCLPEventClass {
 | 
				
			||||||
    bool (*can_handle_event)(uint8_t type);
 | 
					    bool (*can_handle_event)(uint8_t type);
 | 
				
			||||||
} SCLPEventClass;
 | 
					} SCLPEventClass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TYPE_SCLP_EVENT_FACILITY "s390-sclp-event-facility"
 | 
				
			||||||
 | 
					#define EVENT_FACILITY(obj) \
 | 
				
			||||||
 | 
					     OBJECT_CHECK(SCLPEventFacility, (obj), TYPE_SCLP_EVENT_FACILITY)
 | 
				
			||||||
 | 
					#define EVENT_FACILITY_CLASS(klass) \
 | 
				
			||||||
 | 
					     OBJECT_CLASS_CHECK(SCLPEventFacilityClass, (klass), \
 | 
				
			||||||
 | 
					                        TYPE_SCLP_EVENT_FACILITY)
 | 
				
			||||||
 | 
					#define EVENT_FACILITY_GET_CLASS(obj) \
 | 
				
			||||||
 | 
					     OBJECT_GET_CLASS(SCLPEventFacilityClass, (obj), \
 | 
				
			||||||
 | 
					                      TYPE_SCLP_EVENT_FACILITY)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct SCLPEventFacility SCLPEventFacility;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct SCLPEventFacilityClass {
 | 
				
			||||||
 | 
					    DeviceClass parent_class;
 | 
				
			||||||
 | 
					    int (*init)(SCLPEventFacility *ef);
 | 
				
			||||||
 | 
					    void (*command_handler)(SCLPEventFacility *ef, SCCB *sccb, uint64_t code);
 | 
				
			||||||
 | 
					    bool (*event_pending)(SCLPEventFacility *ef);
 | 
				
			||||||
 | 
					} SCLPEventFacilityClass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,33 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * QEMU S390x KVM floating interrupt controller (flic)
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright 2014 IBM Corp.
 | 
				
			||||||
 | 
					 * Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This work is licensed under the terms of the GNU GPL, version 2 or (at
 | 
				
			||||||
 | 
					 * your option) any later version. See the COPYING file in the top-level
 | 
				
			||||||
 | 
					 * directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __KVM_S390_FLIC_H
 | 
				
			||||||
 | 
					#define __KVM_S390_FLIC_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "hw/sysbus.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TYPE_KVM_S390_FLIC "s390-flic"
 | 
				
			||||||
 | 
					#define KVM_S390_FLIC(obj) \
 | 
				
			||||||
 | 
					    OBJECT_CHECK(KVMS390FLICState, (obj), TYPE_KVM_S390_FLIC)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct KVMS390FLICState {
 | 
				
			||||||
 | 
					    SysBusDevice parent_obj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint32_t fd;
 | 
				
			||||||
 | 
					} KVMS390FLICState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_KVM
 | 
				
			||||||
 | 
					void s390_flic_init(void);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					static inline void s390_flic_init(void) { }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* __KVM_S390_FLIC_H */
 | 
				
			||||||
| 
						 | 
					@ -161,30 +161,6 @@ static inline int sccb_data_len(SCCB *sccb)
 | 
				
			||||||
    return be16_to_cpu(sccb->h.length) - sizeof(sccb->h);
 | 
					    return be16_to_cpu(sccb->h.length) - sizeof(sccb->h);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define TYPE_DEVICE_S390_SCLP "s390-sclp-device"
 | 
					 | 
				
			||||||
#define SCLP_S390_DEVICE(obj) \
 | 
					 | 
				
			||||||
     OBJECT_CHECK(S390SCLPDevice, (obj), TYPE_DEVICE_S390_SCLP)
 | 
					 | 
				
			||||||
#define SCLP_S390_DEVICE_CLASS(klass) \
 | 
					 | 
				
			||||||
     OBJECT_CLASS_CHECK(S390SCLPDeviceClass, (klass), \
 | 
					 | 
				
			||||||
             TYPE_DEVICE_S390_SCLP)
 | 
					 | 
				
			||||||
#define SCLP_S390_DEVICE_GET_CLASS(obj) \
 | 
					 | 
				
			||||||
     OBJECT_GET_CLASS(S390SCLPDeviceClass, (obj), \
 | 
					 | 
				
			||||||
             TYPE_DEVICE_S390_SCLP)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SCLPEventFacility SCLPEventFacility;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct S390SCLPDevice {
 | 
					 | 
				
			||||||
    SysBusDevice busdev;
 | 
					 | 
				
			||||||
    SCLPEventFacility *ef;
 | 
					 | 
				
			||||||
    void (*sclp_command_handler)(SCLPEventFacility *ef, SCCB *sccb,
 | 
					 | 
				
			||||||
                                 uint64_t code);
 | 
					 | 
				
			||||||
    bool (*event_pending)(SCLPEventFacility *ef);
 | 
					 | 
				
			||||||
} S390SCLPDevice;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct S390SCLPDeviceClass {
 | 
					 | 
				
			||||||
    DeviceClass qdev;
 | 
					 | 
				
			||||||
    int (*init)(S390SCLPDevice *sdev);
 | 
					 | 
				
			||||||
} S390SCLPDeviceClass;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void s390_sclp_init(void);
 | 
					void s390_sclp_init(void);
 | 
				
			||||||
void sclp_service_interrupt(uint32_t sccb);
 | 
					void sclp_service_interrupt(uint32_t sccb);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,6 +16,22 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define __KVM_S390
 | 
					#define __KVM_S390
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Device control API: s390-specific devices */
 | 
				
			||||||
 | 
					#define KVM_DEV_FLIC_GET_ALL_IRQS	1
 | 
				
			||||||
 | 
					#define KVM_DEV_FLIC_ENQUEUE		2
 | 
				
			||||||
 | 
					#define KVM_DEV_FLIC_CLEAR_IRQS		3
 | 
				
			||||||
 | 
					#define KVM_DEV_FLIC_APF_ENABLE		4
 | 
				
			||||||
 | 
					#define KVM_DEV_FLIC_APF_DISABLE_WAIT	5
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * We can have up to 4*64k pending subchannels + 8 adapter interrupts,
 | 
				
			||||||
 | 
					 * as well as up  to ASYNC_PF_PER_VCPU*KVM_MAX_VCPUS pfault done interrupts.
 | 
				
			||||||
 | 
					 * There are also sclp and machine checks. This gives us
 | 
				
			||||||
 | 
					 * sizeof(kvm_s390_irq)*(4*65536+8+64*64+1+1) = 72 * 266250 = 19170000
 | 
				
			||||||
 | 
					 * Lets round up to 8192 pages.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define KVM_S390_MAX_FLOAT_IRQS	266250
 | 
				
			||||||
 | 
					#define KVM_S390_FLIC_MAX_BUFFER	0x2000000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* for KVM_GET_REGS and KVM_SET_REGS */
 | 
					/* for KVM_GET_REGS and KVM_SET_REGS */
 | 
				
			||||||
struct kvm_regs {
 | 
					struct kvm_regs {
 | 
				
			||||||
	/* general purpose regs for s390 */
 | 
						/* general purpose regs for s390 */
 | 
				
			||||||
| 
						 | 
					@ -57,4 +73,7 @@ struct kvm_sync_regs {
 | 
				
			||||||
#define KVM_REG_S390_EPOCHDIFF	(KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x2)
 | 
					#define KVM_REG_S390_EPOCHDIFF	(KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x2)
 | 
				
			||||||
#define KVM_REG_S390_CPU_TIMER  (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x3)
 | 
					#define KVM_REG_S390_CPU_TIMER  (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x3)
 | 
				
			||||||
#define KVM_REG_S390_CLOCK_COMP (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x4)
 | 
					#define KVM_REG_S390_CLOCK_COMP (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x4)
 | 
				
			||||||
 | 
					#define KVM_REG_S390_PFTOKEN	(KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x5)
 | 
				
			||||||
 | 
					#define KVM_REG_S390_PFCOMPARE	(KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x6)
 | 
				
			||||||
 | 
					#define KVM_REG_S390_PFSELECT	(KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x7)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -413,6 +413,8 @@ struct kvm_s390_psw {
 | 
				
			||||||
#define KVM_S390_PROGRAM_INT		0xfffe0001u
 | 
					#define KVM_S390_PROGRAM_INT		0xfffe0001u
 | 
				
			||||||
#define KVM_S390_SIGP_SET_PREFIX	0xfffe0002u
 | 
					#define KVM_S390_SIGP_SET_PREFIX	0xfffe0002u
 | 
				
			||||||
#define KVM_S390_RESTART		0xfffe0003u
 | 
					#define KVM_S390_RESTART		0xfffe0003u
 | 
				
			||||||
 | 
					#define KVM_S390_INT_PFAULT_INIT	0xfffe0004u
 | 
				
			||||||
 | 
					#define KVM_S390_INT_PFAULT_DONE	0xfffe0005u
 | 
				
			||||||
#define KVM_S390_MCHK			0xfffe1000u
 | 
					#define KVM_S390_MCHK			0xfffe1000u
 | 
				
			||||||
#define KVM_S390_INT_VIRTIO		0xffff2603u
 | 
					#define KVM_S390_INT_VIRTIO		0xffff2603u
 | 
				
			||||||
#define KVM_S390_INT_SERVICE		0xffff2401u
 | 
					#define KVM_S390_INT_SERVICE		0xffff2401u
 | 
				
			||||||
| 
						 | 
					@ -434,6 +436,69 @@ struct kvm_s390_interrupt {
 | 
				
			||||||
	__u64 parm64;
 | 
						__u64 parm64;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct kvm_s390_io_info {
 | 
				
			||||||
 | 
						__u16 subchannel_id;
 | 
				
			||||||
 | 
						__u16 subchannel_nr;
 | 
				
			||||||
 | 
						__u32 io_int_parm;
 | 
				
			||||||
 | 
						__u32 io_int_word;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct kvm_s390_ext_info {
 | 
				
			||||||
 | 
						__u32 ext_params;
 | 
				
			||||||
 | 
						__u32 pad;
 | 
				
			||||||
 | 
						__u64 ext_params2;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct kvm_s390_pgm_info {
 | 
				
			||||||
 | 
						__u64 trans_exc_code;
 | 
				
			||||||
 | 
						__u64 mon_code;
 | 
				
			||||||
 | 
						__u64 per_address;
 | 
				
			||||||
 | 
						__u32 data_exc_code;
 | 
				
			||||||
 | 
						__u16 code;
 | 
				
			||||||
 | 
						__u16 mon_class_nr;
 | 
				
			||||||
 | 
						__u8 per_code;
 | 
				
			||||||
 | 
						__u8 per_atmid;
 | 
				
			||||||
 | 
						__u8 exc_access_id;
 | 
				
			||||||
 | 
						__u8 per_access_id;
 | 
				
			||||||
 | 
						__u8 op_access_id;
 | 
				
			||||||
 | 
						__u8 pad[3];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct kvm_s390_prefix_info {
 | 
				
			||||||
 | 
						__u32 address;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct kvm_s390_extcall_info {
 | 
				
			||||||
 | 
						__u16 code;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct kvm_s390_emerg_info {
 | 
				
			||||||
 | 
						__u16 code;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct kvm_s390_mchk_info {
 | 
				
			||||||
 | 
						__u64 cr14;
 | 
				
			||||||
 | 
						__u64 mcic;
 | 
				
			||||||
 | 
						__u64 failing_storage_address;
 | 
				
			||||||
 | 
						__u32 ext_damage_code;
 | 
				
			||||||
 | 
						__u32 pad;
 | 
				
			||||||
 | 
						__u8 fixed_logout[16];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct kvm_s390_irq {
 | 
				
			||||||
 | 
						__u64 type;
 | 
				
			||||||
 | 
						union {
 | 
				
			||||||
 | 
							struct kvm_s390_io_info io;
 | 
				
			||||||
 | 
							struct kvm_s390_ext_info ext;
 | 
				
			||||||
 | 
							struct kvm_s390_pgm_info pgm;
 | 
				
			||||||
 | 
							struct kvm_s390_emerg_info emerg;
 | 
				
			||||||
 | 
							struct kvm_s390_extcall_info extcall;
 | 
				
			||||||
 | 
							struct kvm_s390_prefix_info prefix;
 | 
				
			||||||
 | 
							struct kvm_s390_mchk_info mchk;
 | 
				
			||||||
 | 
							char reserved[64];
 | 
				
			||||||
 | 
						} u;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* for KVM_SET_GUEST_DEBUG */
 | 
					/* for KVM_SET_GUEST_DEBUG */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define KVM_GUESTDBG_ENABLE		0x00000001
 | 
					#define KVM_GUESTDBG_ENABLE		0x00000001
 | 
				
			||||||
| 
						 | 
					@ -855,6 +920,7 @@ struct kvm_device_attr {
 | 
				
			||||||
#define   KVM_DEV_VFIO_GROUP_ADD			1
 | 
					#define   KVM_DEV_VFIO_GROUP_ADD			1
 | 
				
			||||||
#define   KVM_DEV_VFIO_GROUP_DEL			2
 | 
					#define   KVM_DEV_VFIO_GROUP_DEL			2
 | 
				
			||||||
#define KVM_DEV_TYPE_ARM_VGIC_V2	5
 | 
					#define KVM_DEV_TYPE_ARM_VGIC_V2	5
 | 
				
			||||||
 | 
					#define KVM_DEV_TYPE_FLIC		6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * ioctls for VM fds
 | 
					 * ioctls for VM fds
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
						 | 
					@ -10,7 +10,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "s390-ccw.h"
 | 
					#include "s390-ccw.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct subchannel_id blk_schid;
 | 
					 | 
				
			||||||
char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
 | 
					char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
 | 
				
			||||||
uint64_t boot_value;
 | 
					uint64_t boot_value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,13 +22,13 @@ void virtio_panic(const char *string)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void virtio_setup(uint64_t dev_info)
 | 
					static void virtio_setup(uint64_t dev_info)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    struct subchannel_id blk_schid = { .one = 1 };
 | 
				
			||||||
    struct schib schib;
 | 
					    struct schib schib;
 | 
				
			||||||
    int i;
 | 
					    int i;
 | 
				
			||||||
    int r;
 | 
					    int r;
 | 
				
			||||||
    bool found = false;
 | 
					    bool found = false;
 | 
				
			||||||
    bool check_devno = false;
 | 
					    bool check_devno = false;
 | 
				
			||||||
    uint16_t dev_no = -1;
 | 
					    uint16_t dev_no = -1;
 | 
				
			||||||
    blk_schid.one = 1;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (dev_info != -1) {
 | 
					    if (dev_info != -1) {
 | 
				
			||||||
        check_devno = true;
 | 
					        check_devno = true;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -124,6 +124,7 @@ static void vring_init(struct vring *vr, unsigned int num, void *p,
 | 
				
			||||||
    vr->used->flags = VRING_USED_F_NO_NOTIFY;
 | 
					    vr->used->flags = VRING_USED_F_NO_NOTIFY;
 | 
				
			||||||
    vr->used->idx = 0;
 | 
					    vr->used->idx = 0;
 | 
				
			||||||
    vr->used_idx = 0;
 | 
					    vr->used_idx = 0;
 | 
				
			||||||
 | 
					    vr->next_idx = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    debug_print_addr("init vr", vr);
 | 
					    debug_print_addr("init vr", vr);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -83,6 +83,7 @@ static void s390_cpu_reset(CPUState *s)
 | 
				
			||||||
    S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
 | 
					    S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
 | 
				
			||||||
    CPUS390XState *env = &cpu->env;
 | 
					    CPUS390XState *env = &cpu->env;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    env->pfault_token = -1UL;
 | 
				
			||||||
    s390_del_running_cpu(cpu);
 | 
					    s390_del_running_cpu(cpu);
 | 
				
			||||||
    scc->parent_reset(s);
 | 
					    scc->parent_reset(s);
 | 
				
			||||||
#if !defined(CONFIG_USER_ONLY)
 | 
					#if !defined(CONFIG_USER_ONLY)
 | 
				
			||||||
| 
						 | 
					@ -105,6 +106,17 @@ static void s390_cpu_initial_reset(CPUState *s)
 | 
				
			||||||
    /* architectured initial values for CR 0 and 14 */
 | 
					    /* architectured initial values for CR 0 and 14 */
 | 
				
			||||||
    env->cregs[0] = CR0_RESET;
 | 
					    env->cregs[0] = CR0_RESET;
 | 
				
			||||||
    env->cregs[14] = CR14_RESET;
 | 
					    env->cregs[14] = CR14_RESET;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    env->pfault_token = -1UL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(CONFIG_KVM)
 | 
				
			||||||
 | 
					    /* Reset state inside the kernel that we cannot access yet from QEMU. */
 | 
				
			||||||
 | 
					    if (kvm_enabled()) {
 | 
				
			||||||
 | 
					        if (kvm_vcpu_ioctl(s, KVM_S390_INITIAL_RESET, NULL)) {
 | 
				
			||||||
 | 
					            perror("Initial CPU reset failed");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* CPUClass:reset() */
 | 
					/* CPUClass:reset() */
 | 
				
			||||||
| 
						 | 
					@ -123,6 +135,9 @@ static void s390_cpu_full_reset(CPUState *s)
 | 
				
			||||||
    /* architectured initial values for CR 0 and 14 */
 | 
					    /* architectured initial values for CR 0 and 14 */
 | 
				
			||||||
    env->cregs[0] = CR0_RESET;
 | 
					    env->cregs[0] = CR0_RESET;
 | 
				
			||||||
    env->cregs[14] = CR14_RESET;
 | 
					    env->cregs[14] = CR14_RESET;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    env->pfault_token = -1UL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* set halted to 1 to make sure we can add the cpu in
 | 
					    /* set halted to 1 to make sure we can add the cpu in
 | 
				
			||||||
     * s390_ipl_cpu code, where CPUState::halted is set back to 0
 | 
					     * s390_ipl_cpu code, where CPUState::halted is set back to 0
 | 
				
			||||||
     * after incrementing the cpu counter */
 | 
					     * after incrementing the cpu counter */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -121,6 +121,10 @@ typedef struct CPUS390XState {
 | 
				
			||||||
    uint64_t cputm;
 | 
					    uint64_t cputm;
 | 
				
			||||||
    uint32_t todpr;
 | 
					    uint32_t todpr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint64_t pfault_token;
 | 
				
			||||||
 | 
					    uint64_t pfault_compare;
 | 
				
			||||||
 | 
					    uint64_t pfault_select;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    CPU_COMMON
 | 
					    CPU_COMMON
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* reset does memset(0) up to here */
 | 
					    /* reset does memset(0) up to here */
 | 
				
			||||||
| 
						 | 
					@ -959,7 +963,7 @@ struct sysib_322 {
 | 
				
			||||||
void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr);
 | 
					void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr);
 | 
				
			||||||
int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
 | 
					int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
 | 
				
			||||||
                  target_ulong *raddr, int *flags);
 | 
					                  target_ulong *raddr, int *flags);
 | 
				
			||||||
int sclp_service_call(uint32_t sccb, uint64_t code);
 | 
					int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code);
 | 
				
			||||||
uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
 | 
					uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
 | 
				
			||||||
                 uint64_t vr);
 | 
					                 uint64_t vr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -53,25 +53,28 @@
 | 
				
			||||||
#define IPA0_B9                         0xb900
 | 
					#define IPA0_B9                         0xb900
 | 
				
			||||||
#define IPA0_EB                         0xeb00
 | 
					#define IPA0_EB                         0xeb00
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define PRIV_SCLP_CALL                  0x20
 | 
					#define PRIV_B2_SCLP_CALL               0x20
 | 
				
			||||||
#define PRIV_CSCH                       0x30
 | 
					#define PRIV_B2_CSCH                    0x30
 | 
				
			||||||
#define PRIV_HSCH                       0x31
 | 
					#define PRIV_B2_HSCH                    0x31
 | 
				
			||||||
#define PRIV_MSCH                       0x32
 | 
					#define PRIV_B2_MSCH                    0x32
 | 
				
			||||||
#define PRIV_SSCH                       0x33
 | 
					#define PRIV_B2_SSCH                    0x33
 | 
				
			||||||
#define PRIV_STSCH                      0x34
 | 
					#define PRIV_B2_STSCH                   0x34
 | 
				
			||||||
#define PRIV_TSCH                       0x35
 | 
					#define PRIV_B2_TSCH                    0x35
 | 
				
			||||||
#define PRIV_TPI                        0x36
 | 
					#define PRIV_B2_TPI                     0x36
 | 
				
			||||||
#define PRIV_SAL                        0x37
 | 
					#define PRIV_B2_SAL                     0x37
 | 
				
			||||||
#define PRIV_RSCH                       0x38
 | 
					#define PRIV_B2_RSCH                    0x38
 | 
				
			||||||
#define PRIV_STCRW                      0x39
 | 
					#define PRIV_B2_STCRW                   0x39
 | 
				
			||||||
#define PRIV_STCPS                      0x3a
 | 
					#define PRIV_B2_STCPS                   0x3a
 | 
				
			||||||
#define PRIV_RCHP                       0x3b
 | 
					#define PRIV_B2_RCHP                    0x3b
 | 
				
			||||||
#define PRIV_SCHM                       0x3c
 | 
					#define PRIV_B2_SCHM                    0x3c
 | 
				
			||||||
#define PRIV_CHSC                       0x5f
 | 
					#define PRIV_B2_CHSC                    0x5f
 | 
				
			||||||
#define PRIV_SIGA                       0x74
 | 
					#define PRIV_B2_SIGA                    0x74
 | 
				
			||||||
#define PRIV_XSCH                       0x76
 | 
					#define PRIV_B2_XSCH                    0x76
 | 
				
			||||||
#define PRIV_SQBS                       0x8a
 | 
					
 | 
				
			||||||
#define PRIV_EQBS                       0x9c
 | 
					#define PRIV_EB_SQBS                    0x8a
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PRIV_B9_EQBS                    0x9c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DIAG_IPL                        0x308
 | 
					#define DIAG_IPL                        0x308
 | 
				
			||||||
#define DIAG_KVM_HYPERCALL              0x500
 | 
					#define DIAG_KVM_HYPERCALL              0x500
 | 
				
			||||||
#define DIAG_KVM_BREAKPOINT             0x501
 | 
					#define DIAG_KVM_BREAKPOINT             0x501
 | 
				
			||||||
| 
						 | 
					@ -87,12 +90,14 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int cap_sync_regs;
 | 
					static int cap_sync_regs;
 | 
				
			||||||
 | 
					static int cap_async_pf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void *legacy_s390_alloc(size_t size);
 | 
					static void *legacy_s390_alloc(size_t size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int kvm_arch_init(KVMState *s)
 | 
					int kvm_arch_init(KVMState *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    cap_sync_regs = kvm_check_extension(s, KVM_CAP_SYNC_REGS);
 | 
					    cap_sync_regs = kvm_check_extension(s, KVM_CAP_SYNC_REGS);
 | 
				
			||||||
 | 
					    cap_async_pf = kvm_check_extension(s, KVM_CAP_ASYNC_PF);
 | 
				
			||||||
    if (!kvm_check_extension(s, KVM_CAP_S390_GMAP)
 | 
					    if (!kvm_check_extension(s, KVM_CAP_S390_GMAP)
 | 
				
			||||||
        || !kvm_check_extension(s, KVM_CAP_S390_COW)) {
 | 
					        || !kvm_check_extension(s, KVM_CAP_S390_COW)) {
 | 
				
			||||||
        phys_mem_set_alloc(legacy_s390_alloc);
 | 
					        phys_mem_set_alloc(legacy_s390_alloc);
 | 
				
			||||||
| 
						 | 
					@ -178,6 +183,29 @@ int kvm_arch_put_registers(CPUState *cs, int level)
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (cap_async_pf) {
 | 
				
			||||||
 | 
					        reg.id = KVM_REG_S390_PFTOKEN;
 | 
				
			||||||
 | 
					        reg.addr = (__u64)&(env->pfault_token);
 | 
				
			||||||
 | 
					        ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
 | 
				
			||||||
 | 
					        if (ret < 0) {
 | 
				
			||||||
 | 
					            return ret;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        reg.id = KVM_REG_S390_PFCOMPARE;
 | 
				
			||||||
 | 
					        reg.addr = (__u64)&(env->pfault_compare);
 | 
				
			||||||
 | 
					        ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
 | 
				
			||||||
 | 
					        if (ret < 0) {
 | 
				
			||||||
 | 
					            return ret;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        reg.id = KVM_REG_S390_PFSELECT;
 | 
				
			||||||
 | 
					        reg.addr = (__u64)&(env->pfault_select);
 | 
				
			||||||
 | 
					        ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
 | 
				
			||||||
 | 
					        if (ret < 0) {
 | 
				
			||||||
 | 
					            return ret;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (cap_sync_regs &&
 | 
					    if (cap_sync_regs &&
 | 
				
			||||||
        cs->kvm_run->kvm_valid_regs & KVM_SYNC_ACRS &&
 | 
					        cs->kvm_run->kvm_valid_regs & KVM_SYNC_ACRS &&
 | 
				
			||||||
        cs->kvm_run->kvm_valid_regs & KVM_SYNC_CRS) {
 | 
					        cs->kvm_run->kvm_valid_regs & KVM_SYNC_CRS) {
 | 
				
			||||||
| 
						 | 
					@ -282,6 +310,29 @@ int kvm_arch_get_registers(CPUState *cs)
 | 
				
			||||||
        return r;
 | 
					        return r;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (cap_async_pf) {
 | 
				
			||||||
 | 
					        reg.id = KVM_REG_S390_PFTOKEN;
 | 
				
			||||||
 | 
					        reg.addr = (__u64)&(env->pfault_token);
 | 
				
			||||||
 | 
					        r = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
 | 
				
			||||||
 | 
					        if (r < 0) {
 | 
				
			||||||
 | 
					            return r;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        reg.id = KVM_REG_S390_PFCOMPARE;
 | 
				
			||||||
 | 
					        reg.addr = (__u64)&(env->pfault_compare);
 | 
				
			||||||
 | 
					        r = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
 | 
				
			||||||
 | 
					        if (r < 0) {
 | 
				
			||||||
 | 
					            return r;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        reg.id = KVM_REG_S390_PFSELECT;
 | 
				
			||||||
 | 
					        reg.addr = (__u64)&(env->pfault_select);
 | 
				
			||||||
 | 
					        r = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
 | 
				
			||||||
 | 
					        if (r < 0) {
 | 
				
			||||||
 | 
					            return r;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -392,117 +443,128 @@ static int kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run,
 | 
				
			||||||
                                 uint16_t ipbh0)
 | 
					                                 uint16_t ipbh0)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    CPUS390XState *env = &cpu->env;
 | 
					    CPUS390XState *env = &cpu->env;
 | 
				
			||||||
    uint32_t sccb;
 | 
					    uint64_t sccb;
 | 
				
			||||||
    uint64_t code;
 | 
					    uint32_t code;
 | 
				
			||||||
    int r = 0;
 | 
					    int r = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cpu_synchronize_state(CPU(cpu));
 | 
					    cpu_synchronize_state(CPU(cpu));
 | 
				
			||||||
    if (env->psw.mask & PSW_MASK_PSTATE) {
 | 
					 | 
				
			||||||
        enter_pgmcheck(cpu, PGM_PRIVILEGED);
 | 
					 | 
				
			||||||
        return 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    sccb = env->regs[ipbh0 & 0xf];
 | 
					    sccb = env->regs[ipbh0 & 0xf];
 | 
				
			||||||
    code = env->regs[(ipbh0 & 0xf0) >> 4];
 | 
					    code = env->regs[(ipbh0 & 0xf0) >> 4];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    r = sclp_service_call(sccb, code);
 | 
					    r = sclp_service_call(env, sccb, code);
 | 
				
			||||||
    if (r < 0) {
 | 
					    if (r < 0) {
 | 
				
			||||||
        enter_pgmcheck(cpu, -r);
 | 
					        enter_pgmcheck(cpu, -r);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        setcc(cpu, r);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    setcc(cpu, r);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int kvm_handle_css_inst(S390CPU *cpu, struct kvm_run *run,
 | 
					static int handle_b2(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
 | 
				
			||||||
                               uint8_t ipa0, uint8_t ipa1, uint8_t ipb)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    CPUS390XState *env = &cpu->env;
 | 
					    CPUS390XState *env = &cpu->env;
 | 
				
			||||||
 | 
					    int rc = 0;
 | 
				
			||||||
    if (ipa0 != 0xb2) {
 | 
					    uint16_t ipbh0 = (run->s390_sieic.ipb & 0xffff0000) >> 16;
 | 
				
			||||||
        /* Not handled for now. */
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cpu_synchronize_state(CPU(cpu));
 | 
					    cpu_synchronize_state(CPU(cpu));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    switch (ipa1) {
 | 
					    switch (ipa1) {
 | 
				
			||||||
    case PRIV_XSCH:
 | 
					    case PRIV_B2_XSCH:
 | 
				
			||||||
        ioinst_handle_xsch(cpu, env->regs[1]);
 | 
					        ioinst_handle_xsch(cpu, env->regs[1]);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case PRIV_CSCH:
 | 
					    case PRIV_B2_CSCH:
 | 
				
			||||||
        ioinst_handle_csch(cpu, env->regs[1]);
 | 
					        ioinst_handle_csch(cpu, env->regs[1]);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case PRIV_HSCH:
 | 
					    case PRIV_B2_HSCH:
 | 
				
			||||||
        ioinst_handle_hsch(cpu, env->regs[1]);
 | 
					        ioinst_handle_hsch(cpu, env->regs[1]);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case PRIV_MSCH:
 | 
					    case PRIV_B2_MSCH:
 | 
				
			||||||
        ioinst_handle_msch(cpu, env->regs[1], run->s390_sieic.ipb);
 | 
					        ioinst_handle_msch(cpu, env->regs[1], run->s390_sieic.ipb);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case PRIV_SSCH:
 | 
					    case PRIV_B2_SSCH:
 | 
				
			||||||
        ioinst_handle_ssch(cpu, env->regs[1], run->s390_sieic.ipb);
 | 
					        ioinst_handle_ssch(cpu, env->regs[1], run->s390_sieic.ipb);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case PRIV_STCRW:
 | 
					    case PRIV_B2_STCRW:
 | 
				
			||||||
        ioinst_handle_stcrw(cpu, run->s390_sieic.ipb);
 | 
					        ioinst_handle_stcrw(cpu, run->s390_sieic.ipb);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case PRIV_STSCH:
 | 
					    case PRIV_B2_STSCH:
 | 
				
			||||||
        ioinst_handle_stsch(cpu, env->regs[1], run->s390_sieic.ipb);
 | 
					        ioinst_handle_stsch(cpu, env->regs[1], run->s390_sieic.ipb);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case PRIV_TSCH:
 | 
					    case PRIV_B2_TSCH:
 | 
				
			||||||
        /* We should only get tsch via KVM_EXIT_S390_TSCH. */
 | 
					        /* We should only get tsch via KVM_EXIT_S390_TSCH. */
 | 
				
			||||||
        fprintf(stderr, "Spurious tsch intercept\n");
 | 
					        fprintf(stderr, "Spurious tsch intercept\n");
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case PRIV_CHSC:
 | 
					    case PRIV_B2_CHSC:
 | 
				
			||||||
        ioinst_handle_chsc(cpu, run->s390_sieic.ipb);
 | 
					        ioinst_handle_chsc(cpu, run->s390_sieic.ipb);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case PRIV_TPI:
 | 
					    case PRIV_B2_TPI:
 | 
				
			||||||
        /* This should have been handled by kvm already. */
 | 
					        /* This should have been handled by kvm already. */
 | 
				
			||||||
        fprintf(stderr, "Spurious tpi intercept\n");
 | 
					        fprintf(stderr, "Spurious tpi intercept\n");
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case PRIV_SCHM:
 | 
					    case PRIV_B2_SCHM:
 | 
				
			||||||
        ioinst_handle_schm(cpu, env->regs[1], env->regs[2],
 | 
					        ioinst_handle_schm(cpu, env->regs[1], env->regs[2],
 | 
				
			||||||
                           run->s390_sieic.ipb);
 | 
					                           run->s390_sieic.ipb);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case PRIV_RSCH:
 | 
					    case PRIV_B2_RSCH:
 | 
				
			||||||
        ioinst_handle_rsch(cpu, env->regs[1]);
 | 
					        ioinst_handle_rsch(cpu, env->regs[1]);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case PRIV_RCHP:
 | 
					    case PRIV_B2_RCHP:
 | 
				
			||||||
        ioinst_handle_rchp(cpu, env->regs[1]);
 | 
					        ioinst_handle_rchp(cpu, env->regs[1]);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case PRIV_STCPS:
 | 
					    case PRIV_B2_STCPS:
 | 
				
			||||||
        /* We do not provide this instruction, it is suppressed. */
 | 
					        /* We do not provide this instruction, it is suppressed. */
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case PRIV_SAL:
 | 
					    case PRIV_B2_SAL:
 | 
				
			||||||
        ioinst_handle_sal(cpu, env->regs[1]);
 | 
					        ioinst_handle_sal(cpu, env->regs[1]);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case PRIV_SIGA:
 | 
					    case PRIV_B2_SIGA:
 | 
				
			||||||
        /* Not provided, set CC = 3 for subchannel not operational */
 | 
					        /* Not provided, set CC = 3 for subchannel not operational */
 | 
				
			||||||
        setcc(cpu, 3);
 | 
					        setcc(cpu, 3);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					    case PRIV_B2_SCLP_CALL:
 | 
				
			||||||
 | 
					        rc = kvm_sclp_service_call(cpu, run, ipbh0);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
        return -1;
 | 
					        rc = -1;
 | 
				
			||||||
 | 
					        DPRINTF("KVM: unhandled PRIV: 0xb2%x\n", ipa1);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int handle_priv(S390CPU *cpu, struct kvm_run *run,
 | 
					static int handle_b9(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
 | 
				
			||||||
                       uint8_t ipa0, uint8_t ipa1)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int r = 0;
 | 
					    int r = 0;
 | 
				
			||||||
    uint16_t ipbh0 = (run->s390_sieic.ipb & 0xffff0000) >> 16;
 | 
					 | 
				
			||||||
    uint8_t ipb = run->s390_sieic.ipb & 0xff;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DPRINTF("KVM: PRIV: %d\n", ipa1);
 | 
					 | 
				
			||||||
    switch (ipa1) {
 | 
					    switch (ipa1) {
 | 
				
			||||||
        case PRIV_SCLP_CALL:
 | 
					    case PRIV_B9_EQBS:
 | 
				
			||||||
            r = kvm_sclp_service_call(cpu, run, ipbh0);
 | 
					        /* just inject exception */
 | 
				
			||||||
            break;
 | 
					        r = -1;
 | 
				
			||||||
        default:
 | 
					        break;
 | 
				
			||||||
            r = kvm_handle_css_inst(cpu, run, ipa0, ipa1, ipb);
 | 
					    default:
 | 
				
			||||||
            if (r == -1) {
 | 
					        r = -1;
 | 
				
			||||||
                DPRINTF("KVM: unhandled PRIV: 0x%x\n", ipa1);
 | 
					        DPRINTF("KVM: unhandled PRIV: 0xb9%x\n", ipa1);
 | 
				
			||||||
            }
 | 
					        break;
 | 
				
			||||||
            break;
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return r;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int handle_eb(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int r = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (ipa1) {
 | 
				
			||||||
 | 
					    case PRIV_EB_SQBS:
 | 
				
			||||||
 | 
					        /* just inject exception */
 | 
				
			||||||
 | 
					        r = -1;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        r = -1;
 | 
				
			||||||
 | 
					        DPRINTF("KVM: unhandled PRIV: 0xeb%x\n", ipa1);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return r;
 | 
					    return r;
 | 
				
			||||||
| 
						 | 
					@ -511,11 +573,16 @@ static int handle_priv(S390CPU *cpu, struct kvm_run *run,
 | 
				
			||||||
static int handle_hypercall(S390CPU *cpu, struct kvm_run *run)
 | 
					static int handle_hypercall(S390CPU *cpu, struct kvm_run *run)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    CPUS390XState *env = &cpu->env;
 | 
					    CPUS390XState *env = &cpu->env;
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cpu_synchronize_state(CPU(cpu));
 | 
					    cpu_synchronize_state(CPU(cpu));
 | 
				
			||||||
    env->regs[2] = s390_virtio_hypercall(env);
 | 
					    ret = s390_virtio_hypercall(env);
 | 
				
			||||||
 | 
					    if (ret == -EINVAL) {
 | 
				
			||||||
 | 
					        enter_pgmcheck(cpu, PGM_SPECIFICATION);
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void kvm_handle_diag_308(S390CPU *cpu, struct kvm_run *run)
 | 
					static void kvm_handle_diag_308(S390CPU *cpu, struct kvm_run *run)
 | 
				
			||||||
| 
						 | 
					@ -576,25 +643,22 @@ int kvm_s390_cpu_restart(S390CPU *cpu)
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int s390_cpu_initial_reset(S390CPU *cpu)
 | 
					static void sigp_initial_cpu_reset(void *arg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    CPUState *cs = CPU(cpu);
 | 
					    CPUState *cpu = arg;
 | 
				
			||||||
    CPUS390XState *env = &cpu->env;
 | 
					    S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
 | 
				
			||||||
    int i;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    s390_del_running_cpu(cpu);
 | 
					    cpu_synchronize_state(cpu);
 | 
				
			||||||
    if (kvm_vcpu_ioctl(cs, KVM_S390_INITIAL_RESET, NULL) < 0) {
 | 
					    scc->initial_cpu_reset(cpu);
 | 
				
			||||||
        perror("cannot init reset vcpu");
 | 
					}
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Manually zero out all registers */
 | 
					static void sigp_cpu_reset(void *arg)
 | 
				
			||||||
    cpu_synchronize_state(cs);
 | 
					{
 | 
				
			||||||
    for (i = 0; i < 16; i++) {
 | 
					    CPUState *cpu = arg;
 | 
				
			||||||
        env->regs[i] = 0;
 | 
					    S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DPRINTF("DONE: SIGP initial reset: %p\n", env);
 | 
					    cpu_synchronize_state(cpu);
 | 
				
			||||||
    return 0;
 | 
					    scc->cpu_reset(cpu);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SIGP_ORDER_MASK 0x000000ff
 | 
					#define SIGP_ORDER_MASK 0x000000ff
 | 
				
			||||||
| 
						 | 
					@ -628,10 +692,17 @@ static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
 | 
				
			||||||
        cc = kvm_s390_cpu_restart(target_cpu);
 | 
					        cc = kvm_s390_cpu_restart(target_cpu);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case SIGP_SET_ARCH:
 | 
					    case SIGP_SET_ARCH:
 | 
				
			||||||
        /* make the caller panic */
 | 
					        *statusreg &= 0xffffffff00000000UL;
 | 
				
			||||||
        return -1;
 | 
					        *statusreg |= SIGP_STAT_INVALID_PARAMETER;
 | 
				
			||||||
 | 
					        cc = 1;   /* status stored */
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
    case SIGP_INITIAL_CPU_RESET:
 | 
					    case SIGP_INITIAL_CPU_RESET:
 | 
				
			||||||
        cc = s390_cpu_initial_reset(target_cpu);
 | 
					        run_on_cpu(CPU(target_cpu), sigp_initial_cpu_reset, CPU(target_cpu));
 | 
				
			||||||
 | 
					        cc = 0;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case SIGP_CPU_RESET:
 | 
				
			||||||
 | 
					        run_on_cpu(CPU(target_cpu), sigp_cpu_reset, CPU(target_cpu));
 | 
				
			||||||
 | 
					        cc = 0;
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
        DPRINTF("KVM: unknown SIGP: 0x%x\n", order_code);
 | 
					        DPRINTF("KVM: unknown SIGP: 0x%x\n", order_code);
 | 
				
			||||||
| 
						 | 
					@ -656,9 +727,13 @@ static void handle_instruction(S390CPU *cpu, struct kvm_run *run)
 | 
				
			||||||
            run->s390_sieic.ipa, run->s390_sieic.ipb);
 | 
					            run->s390_sieic.ipa, run->s390_sieic.ipb);
 | 
				
			||||||
    switch (ipa0) {
 | 
					    switch (ipa0) {
 | 
				
			||||||
    case IPA0_B2:
 | 
					    case IPA0_B2:
 | 
				
			||||||
 | 
					        r = handle_b2(cpu, run, ipa1);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
    case IPA0_B9:
 | 
					    case IPA0_B9:
 | 
				
			||||||
 | 
					        r = handle_b9(cpu, run, ipa1);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
    case IPA0_EB:
 | 
					    case IPA0_EB:
 | 
				
			||||||
        r = handle_priv(cpu, run, ipa0 >> 8, ipa1);
 | 
					        r = handle_eb(cpu, run, ipa1);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case IPA0_DIAG:
 | 
					    case IPA0_DIAG:
 | 
				
			||||||
        r = handle_diag(cpu, run, run->s390_sieic.ipb);
 | 
					        r = handle_diag(cpu, run, run->s390_sieic.ipb);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -93,7 +93,7 @@ void program_interrupt(CPUS390XState *env, uint32_t code, int ilen)
 | 
				
			||||||
/* SCLP service call */
 | 
					/* SCLP service call */
 | 
				
			||||||
uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2)
 | 
					uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int r = sclp_service_call(r1, r2);
 | 
					    int r = sclp_service_call(env, r1, r2);
 | 
				
			||||||
    if (r < 0) {
 | 
					    if (r < 0) {
 | 
				
			||||||
        program_interrupt(env, -r, 4);
 | 
					        program_interrupt(env, -r, 4);
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1162,6 +1162,11 @@ css_io_interrupt(int cssid, int ssid, int schid, uint32_t intparm, uint8_t isc,
 | 
				
			||||||
virtio_ccw_interpret_ccw(int cssid, int ssid, int schid, int cmd_code) "VIRTIO-CCW: %x.%x.%04x: interpret command %x"
 | 
					virtio_ccw_interpret_ccw(int cssid, int ssid, int schid, int cmd_code) "VIRTIO-CCW: %x.%x.%04x: interpret command %x"
 | 
				
			||||||
virtio_ccw_new_device(int cssid, int ssid, int schid, int devno, const char *devno_mode) "VIRTIO-CCW: add subchannel %x.%x.%04x, devno %04x (%s)"
 | 
					virtio_ccw_new_device(int cssid, int ssid, int schid, int devno, const char *devno_mode) "VIRTIO-CCW: add subchannel %x.%x.%04x, devno %04x (%s)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# hw/intc/s390_flic.c
 | 
				
			||||||
 | 
					flic_create_device(int err) "flic: create device failed %d"
 | 
				
			||||||
 | 
					flic_no_device_api(int err) "flic: no Device Contral API support %d"
 | 
				
			||||||
 | 
					flic_reset_failed(int err) "flic: reset failed %d"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# migration.c
 | 
					# migration.c
 | 
				
			||||||
migrate_set_state(int new_state) "new state %d"
 | 
					migrate_set_state(int new_state) "new state %d"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue