From 216db403d0b032563d82e107429626c08d825535 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Fri, 7 Feb 2014 12:13:39 +0100 Subject: [PATCH 01/22] update linux headers to kvm/next This updates the kvm headers to commit d3714010c307d26df251c45be9cd12ab6d41f0c4 KVM: x86: emulator_cmpxchg_emulated should mark_page_dirty in kvm/next. Signed-off-by: Christian Borntraeger --- linux-headers/asm-arm/kvm.h | 28 ++++++++++++++ linux-headers/asm-arm64/kvm.h | 30 ++++++++++++++- linux-headers/asm-powerpc/kvm.h | 3 ++ linux-headers/asm-s390/kvm.h | 19 ++++++++++ linux-headers/asm-x86/hyperv.h | 16 ++++++-- linux-headers/linux/kvm.h | 67 +++++++++++++++++++++++++++++++++ 6 files changed, 159 insertions(+), 4 deletions(-) diff --git a/linux-headers/asm-arm/kvm.h b/linux-headers/asm-arm/kvm.h index c498b60c05..ef0c8785ba 100644 --- a/linux-headers/asm-arm/kvm.h +++ b/linux-headers/asm-arm/kvm.h @@ -119,6 +119,26 @@ struct kvm_arch_memory_slot { #define KVM_REG_ARM_32_CRN_MASK 0x0000000000007800 #define KVM_REG_ARM_32_CRN_SHIFT 11 +#define ARM_CP15_REG_SHIFT_MASK(x,n) \ + (((x) << KVM_REG_ARM_ ## n ## _SHIFT) & KVM_REG_ARM_ ## n ## _MASK) + +#define __ARM_CP15_REG(op1,crn,crm,op2) \ + (KVM_REG_ARM | (15 << KVM_REG_ARM_COPROC_SHIFT) | \ + ARM_CP15_REG_SHIFT_MASK(op1, OPC1) | \ + ARM_CP15_REG_SHIFT_MASK(crn, 32_CRN) | \ + ARM_CP15_REG_SHIFT_MASK(crm, CRM) | \ + ARM_CP15_REG_SHIFT_MASK(op2, 32_OPC2)) + +#define ARM_CP15_REG32(...) (__ARM_CP15_REG(__VA_ARGS__) | KVM_REG_SIZE_U32) + +#define __ARM_CP15_REG64(op1,crm) \ + (__ARM_CP15_REG(op1, 0, crm, 0) | KVM_REG_SIZE_U64) +#define ARM_CP15_REG64(...) __ARM_CP15_REG64(__VA_ARGS__) + +#define KVM_REG_ARM_TIMER_CTL ARM_CP15_REG32(0, 14, 3, 1) +#define KVM_REG_ARM_TIMER_CNT ARM_CP15_REG64(1, 14) +#define KVM_REG_ARM_TIMER_CVAL ARM_CP15_REG64(3, 14) + /* Normal registers are mapped as coprocessor 16. */ #define KVM_REG_ARM_CORE (0x0010 << KVM_REG_ARM_COPROC_SHIFT) #define KVM_REG_ARM_CORE_REG(name) (offsetof(struct kvm_regs, name) / 4) @@ -143,6 +163,14 @@ struct kvm_arch_memory_slot { #define KVM_REG_ARM_VFP_FPINST 0x1009 #define KVM_REG_ARM_VFP_FPINST2 0x100A +/* Device Control API: ARM VGIC */ +#define KVM_DEV_ARM_VGIC_GRP_ADDR 0 +#define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 +#define KVM_DEV_ARM_VGIC_GRP_CPU_REGS 2 +#define KVM_DEV_ARM_VGIC_CPUID_SHIFT 32 +#define KVM_DEV_ARM_VGIC_CPUID_MASK (0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT) +#define KVM_DEV_ARM_VGIC_OFFSET_SHIFT 0 +#define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT) /* KVM_IRQ_LINE irq field index values */ #define KVM_ARM_IRQ_TYPE_SHIFT 24 diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h index 5031f42639..eaf54a30be 100644 --- a/linux-headers/asm-arm64/kvm.h +++ b/linux-headers/asm-arm64/kvm.h @@ -55,8 +55,9 @@ struct kvm_regs { #define KVM_ARM_TARGET_AEM_V8 0 #define KVM_ARM_TARGET_FOUNDATION_V8 1 #define KVM_ARM_TARGET_CORTEX_A57 2 +#define KVM_ARM_TARGET_XGENE_POTENZA 3 -#define KVM_ARM_NUM_TARGETS 3 +#define KVM_ARM_NUM_TARGETS 4 /* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */ #define KVM_ARM_DEVICE_TYPE_SHIFT 0 @@ -129,6 +130,33 @@ struct kvm_arch_memory_slot { #define KVM_REG_ARM64_SYSREG_OP2_MASK 0x0000000000000007 #define KVM_REG_ARM64_SYSREG_OP2_SHIFT 0 +#define ARM64_SYS_REG_SHIFT_MASK(x,n) \ + (((x) << KVM_REG_ARM64_SYSREG_ ## n ## _SHIFT) & \ + KVM_REG_ARM64_SYSREG_ ## n ## _MASK) + +#define __ARM64_SYS_REG(op0,op1,crn,crm,op2) \ + (KVM_REG_ARM64 | KVM_REG_ARM64_SYSREG | \ + ARM64_SYS_REG_SHIFT_MASK(op0, OP0) | \ + ARM64_SYS_REG_SHIFT_MASK(op1, OP1) | \ + ARM64_SYS_REG_SHIFT_MASK(crn, CRN) | \ + ARM64_SYS_REG_SHIFT_MASK(crm, CRM) | \ + ARM64_SYS_REG_SHIFT_MASK(op2, OP2)) + +#define ARM64_SYS_REG(...) (__ARM64_SYS_REG(__VA_ARGS__) | KVM_REG_SIZE_U64) + +#define KVM_REG_ARM_TIMER_CTL ARM64_SYS_REG(3, 3, 14, 3, 1) +#define KVM_REG_ARM_TIMER_CNT ARM64_SYS_REG(3, 3, 14, 3, 2) +#define KVM_REG_ARM_TIMER_CVAL ARM64_SYS_REG(3, 3, 14, 0, 2) + +/* Device Control API: ARM VGIC */ +#define KVM_DEV_ARM_VGIC_GRP_ADDR 0 +#define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 +#define KVM_DEV_ARM_VGIC_GRP_CPU_REGS 2 +#define KVM_DEV_ARM_VGIC_CPUID_SHIFT 32 +#define KVM_DEV_ARM_VGIC_CPUID_MASK (0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT) +#define KVM_DEV_ARM_VGIC_OFFSET_SHIFT 0 +#define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT) + /* KVM_IRQ_LINE irq field index values */ #define KVM_ARM_IRQ_TYPE_SHIFT 24 #define KVM_ARM_IRQ_TYPE_MASK 0xff diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h index 6836ec79a8..a6665be4f3 100644 --- a/linux-headers/asm-powerpc/kvm.h +++ b/linux-headers/asm-powerpc/kvm.h @@ -545,6 +545,7 @@ struct kvm_get_htab_header { #define KVM_REG_PPC_TCSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb1) #define KVM_REG_PPC_PID (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb2) #define KVM_REG_PPC_ACOP (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb3) +#define KVM_REG_PPC_WORT (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb4) #define KVM_REG_PPC_VRSAVE (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb4) #define KVM_REG_PPC_LPCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb5) @@ -553,6 +554,8 @@ struct kvm_get_htab_header { /* Architecture compatibility level */ #define KVM_REG_PPC_ARCH_COMPAT (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb7) +#define KVM_REG_PPC_DABRX (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb8) + /* Transactional Memory checkpointed state: * This is all GPRs, all VSX regs and a subset of SPRs */ diff --git a/linux-headers/asm-s390/kvm.h b/linux-headers/asm-s390/kvm.h index d25da598ec..cb4c1eb8a0 100644 --- a/linux-headers/asm-s390/kvm.h +++ b/linux-headers/asm-s390/kvm.h @@ -16,6 +16,22 @@ #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 */ struct kvm_regs { /* 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_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_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 diff --git a/linux-headers/asm-x86/hyperv.h b/linux-headers/asm-x86/hyperv.h index 3b400ee9f7..462efe746d 100644 --- a/linux-headers/asm-x86/hyperv.h +++ b/linux-headers/asm-x86/hyperv.h @@ -28,6 +28,9 @@ /* Partition Reference Counter (HV_X64_MSR_TIME_REF_COUNT) available*/ #define HV_X64_MSR_TIME_REF_COUNT_AVAILABLE (1 << 1) +/* A partition's reference time stamp counter (TSC) page */ +#define HV_X64_MSR_REFERENCE_TSC 0x40000021 + /* * There is a single feature flag that signifies the presence of the MSR * that can be used to retrieve both the local APIC Timer frequency as @@ -149,9 +152,6 @@ /* MSR used to read the per-partition time reference counter */ #define HV_X64_MSR_TIME_REF_COUNT 0x40000020 -/* A partition's reference time stamp counter (TSC) page */ -#define HV_X64_MSR_REFERENCE_TSC 0x40000021 - /* MSR used to retrieve the TSC frequency */ #define HV_X64_MSR_TSC_FREQUENCY 0x40000022 @@ -201,6 +201,9 @@ #define HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_MASK \ (~((1ull << HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT) - 1)) +#define HV_X64_MSR_TSC_REFERENCE_ENABLE 0x00000001 +#define HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT 12 + #define HV_PROCESSOR_POWER_STATE_C0 0 #define HV_PROCESSOR_POWER_STATE_C1 1 #define HV_PROCESSOR_POWER_STATE_C2 2 @@ -213,4 +216,11 @@ #define HV_STATUS_INVALID_ALIGNMENT 4 #define HV_STATUS_INSUFFICIENT_BUFFERS 19 +typedef struct _HV_REFERENCE_TSC_PAGE { + __u32 tsc_sequence; + __u32 res1; + __u64 tsc_scale; + __s64 tsc_offset; +} HV_REFERENCE_TSC_PAGE, *PHV_REFERENCE_TSC_PAGE; + #endif diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 999fb135e1..e27a4b33cf 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -413,6 +413,8 @@ struct kvm_s390_psw { #define KVM_S390_PROGRAM_INT 0xfffe0001u #define KVM_S390_SIGP_SET_PREFIX 0xfffe0002u #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_INT_VIRTIO 0xffff2603u #define KVM_S390_INT_SERVICE 0xffff2401u @@ -434,6 +436,69 @@ struct kvm_s390_interrupt { __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 */ #define KVM_GUESTDBG_ENABLE 0x00000001 @@ -854,6 +919,8 @@ struct kvm_device_attr { #define KVM_DEV_VFIO_GROUP 1 #define KVM_DEV_VFIO_GROUP_ADD 1 #define KVM_DEV_VFIO_GROUP_DEL 2 +#define KVM_DEV_TYPE_ARM_VGIC_V2 5 +#define KVM_DEV_TYPE_FLIC 6 /* * ioctls for VM fds From 3a553fc65826e0e682ed0fff770ad0d421c6d407 Mon Sep 17 00:00:00 2001 From: Jens Freimann Date: Tue, 16 Jul 2013 09:04:04 +0200 Subject: [PATCH 02/22] s390x/kvm: implement floating-interrupt controller device This patch implements a floating-interrupt controller device (flic) which interacts with the s390 flic kvm_device. Signed-off-by: Jens Freimann Reviewed-by: Cornelia Huck Signed-off-by: Christian Borntraeger --- default-configs/s390x-softmmu.mak | 1 + hw/intc/Makefile.objs | 1 + hw/intc/s390_flic.c | 286 ++++++++++++++++++++++++++++++ hw/s390x/s390-virtio-ccw.c | 8 +- hw/s390x/s390-virtio.c | 2 + include/hw/s390x/s390_flic.h | 33 ++++ trace-events | 5 + 7 files changed, 335 insertions(+), 1 deletion(-) create mode 100644 hw/intc/s390_flic.c create mode 100644 include/hw/s390x/s390_flic.h diff --git a/default-configs/s390x-softmmu.mak b/default-configs/s390x-softmmu.mak index 81fbc68654..d843dc0d57 100644 --- a/default-configs/s390x-softmmu.mak +++ b/default-configs/s390x-softmmu.mak @@ -1,2 +1,3 @@ CONFIG_VIRTIO=y CONFIG_SCLPCONSOLE=y +CONFIG_S390_FLIC=$(CONFIG_KVM) diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs index 60eb936e0d..c8a2318d56 100644 --- a/hw/intc/Makefile.objs +++ b/hw/intc/Makefile.objs @@ -25,3 +25,4 @@ obj-$(CONFIG_SH4) += sh_intc.o obj-$(CONFIG_XICS) += xics.o obj-$(CONFIG_XICS_KVM) += xics_kvm.o obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o +obj-$(CONFIG_S390_FLIC) += s390_flic.o diff --git a/hw/intc/s390_flic.c b/hw/intc/s390_flic.c new file mode 100644 index 0000000000..1a7876da78 --- /dev/null +++ b/hw/intc/s390_flic.c @@ -0,0 +1,286 @@ +/* + * QEMU S390x KVM floating interrupt controller (flic) + * + * Copyright 2014 IBM Corp. + * Author(s): Jens Freimann + * + * 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 +#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; +} + +/** 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; + + 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; + } + + 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; + } + + rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr); + if (rc) { + trace_flic_reset_failed(errno); + } +} + +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) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 733d988871..0d4f6ae2f3 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -13,13 +13,14 @@ #include "exec/address-spaces.h" #include "s390-virtio.h" #include "hw/s390x/sclp.h" +#include "hw/s390x/s390_flic.h" #include "ioinst.h" #include "css.h" #include "virtio-ccw.h" void io_subsystem_reset(void) { - DeviceState *css, *sclp; + DeviceState *css, *sclp, *flic; css = DEVICE(object_resolve_path_type("", "virtual-css-bridge", NULL)); if (css) { @@ -30,6 +31,10 @@ void io_subsystem_reset(void) if (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) @@ -99,6 +104,7 @@ static void ccw_init(QEMUMachineInitArgs *args) s390_sclp_init(); s390_init_ipl_dev(args->kernel_filename, args->kernel_cmdline, args->initrd_filename, "s390-ccw.img"); + s390_flic_init(); /* register hypercalls */ virtio_ccw_register_hcalls(); diff --git a/hw/s390x/s390-virtio.c b/hw/s390x/s390-virtio.c index 9eeda97920..0f03fd18b9 100644 --- a/hw/s390x/s390-virtio.c +++ b/hw/s390x/s390-virtio.c @@ -36,6 +36,7 @@ #include "hw/s390x/s390-virtio-bus.h" #include "hw/s390x/sclp.h" +#include "hw/s390x/s390_flic.h" #include "hw/s390x/s390-virtio.h" //#define DEBUG_S390 @@ -251,6 +252,7 @@ static void s390_init(QEMUMachineInitArgs *args) s390_sclp_init(); s390_init_ipl_dev(args->kernel_filename, args->kernel_cmdline, args->initrd_filename, ZIPL_FILENAME); + s390_flic_init(); /* register hypercalls */ s390_virtio_register_hcalls(); diff --git a/include/hw/s390x/s390_flic.h b/include/hw/s390x/s390_flic.h new file mode 100644 index 0000000000..497b219e30 --- /dev/null +++ b/include/hw/s390x/s390_flic.h @@ -0,0 +1,33 @@ +/* + * QEMU S390x KVM floating interrupt controller (flic) + * + * Copyright 2014 IBM Corp. + * Author(s): Jens Freimann + * + * 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 */ diff --git a/trace-events b/trace-events index 37130638ff..8bc7cc42e8 100644 --- a/trace-events +++ b/trace-events @@ -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_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 migrate_set_state(int new_state) "new state %d" From 819bd3091e986c1b6b10203a7138a53b849a53e0 Mon Sep 17 00:00:00 2001 From: Dominik Dingel Date: Thu, 5 Sep 2013 13:54:39 +0200 Subject: [PATCH 03/22] s390x/async_pf: Check for apf extension and enable pfault S390 can also use async page faults, to enhance guest scheduling. In case of live migration we want to disable the feature and let all pending request finish. Signed-off-by: Dominik Dingel Signed-off-by: Jens Freimann Signed-off-by: Christian Borntraeger --- hw/intc/s390_flic.c | 36 ++++++++++++++++++++++++++++++++++ target-s390x/cpu.c | 6 ++++++ target-s390x/cpu.h | 4 ++++ target-s390x/kvm.c | 48 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+) diff --git a/hw/intc/s390_flic.c b/hw/intc/s390_flic.c index 1a7876da78..b2ef3e3f8e 100644 --- a/hw/intc/s390_flic.c +++ b/hw/intc/s390_flic.c @@ -63,6 +63,34 @@ static int flic_get_all_irqs(KVMS390FLICState *flic, 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 @@ -136,6 +164,8 @@ static void kvm_flic_save(QEMUFile *f, void *opaque) 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 @@ -184,6 +214,8 @@ static int kvm_flic_load(QEMUFile *f, void *opaque, int version_id) goto out; } + flic_enable_pfault((struct KVMS390FLICState *) opaque); + count = qemu_get_be64(f); len = count * sizeof(struct kvm_s390_irq); if (count == FLIC_FAILED) { @@ -256,10 +288,14 @@ static void kvm_s390_flic_reset(DeviceState *dev) 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) diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index ff57b806e4..f1319e55a6 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -83,6 +83,7 @@ static void s390_cpu_reset(CPUState *s) S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); CPUS390XState *env = &cpu->env; + env->pfault_token = -1UL; s390_del_running_cpu(cpu); scc->parent_reset(s); #if !defined(CONFIG_USER_ONLY) @@ -105,6 +106,8 @@ static void s390_cpu_initial_reset(CPUState *s) /* architectured initial values for CR 0 and 14 */ env->cregs[0] = CR0_RESET; env->cregs[14] = CR14_RESET; + + env->pfault_token = -1UL; } /* CPUClass:reset() */ @@ -123,6 +126,9 @@ static void s390_cpu_full_reset(CPUState *s) /* architectured initial values for CR 0 and 14 */ env->cregs[0] = CR0_RESET; env->cregs[14] = CR14_RESET; + + env->pfault_token = -1UL; + /* 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 * after incrementing the cpu counter */ diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 96c2b4a7e9..b09ff92099 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -121,6 +121,10 @@ typedef struct CPUS390XState { uint64_t cputm; uint32_t todpr; + uint64_t pfault_token; + uint64_t pfault_compare; + uint64_t pfault_select; + CPU_COMMON /* reset does memset(0) up to here */ diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index f60ccdc326..9430a35b02 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -87,12 +87,14 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = { }; static int cap_sync_regs; +static int cap_async_pf; static void *legacy_s390_alloc(size_t size); int kvm_arch_init(KVMState *s) { 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) || !kvm_check_extension(s, KVM_CAP_S390_COW)) { phys_mem_set_alloc(legacy_s390_alloc); @@ -178,6 +180,29 @@ int kvm_arch_put_registers(CPUState *cs, int level) 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 && cs->kvm_run->kvm_valid_regs & KVM_SYNC_ACRS && cs->kvm_run->kvm_valid_regs & KVM_SYNC_CRS) { @@ -282,6 +307,29 @@ int kvm_arch_get_registers(CPUState *cs) 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; } From 0788082a4b3f41cb453b654d1a66f87adfa794a9 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 22 Jan 2014 17:02:46 +0100 Subject: [PATCH 04/22] s390x/kvm: Fixed bad SIGP SET-ARCHITECTURE handler The SET-ARCHITECTURE handler in QEMU caused a program interruption. This is wrong according to the "Principles of Operations" specification (since SIGP should never cause a program interrupt) and was likely only introduced for debugging purposes. Since we handle SET-ARCHITECTURE in the kernel already and only dropped to user space in case of bad mode parameters, we should just report INVALID PARAMETER in QEMU instead. Signed-off-by: Thomas Huth Reviewed-by: Cornelia Huck Signed-off-by: Christian Borntraeger --- target-s390x/kvm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 9430a35b02..b93fe84121 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -676,8 +676,10 @@ static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) cc = kvm_s390_cpu_restart(target_cpu); break; case SIGP_SET_ARCH: - /* make the caller panic */ - return -1; + *statusreg &= 0xffffffff00000000UL; + *statusreg |= SIGP_STAT_INVALID_PARAMETER; + cc = 1; /* status stored */ + break; case SIGP_INITIAL_CPU_RESET: cc = s390_cpu_initial_reset(target_cpu); break; From f2c55d1735175ab37ab9f69854460087112d2756 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 13 Jan 2014 09:26:49 +0100 Subject: [PATCH 05/22] s390x/virtio-hcall: Add range check for hypervisor call The handler for diag 500 did not check whether the requested function was in the supported range, so illegal values could crash QEMU in the worst case. Signed-off-by: Thomas Huth Reviewed-by: Cornelia Huck Signed-off-by: Christian Borntraeger CC: qemu-stable@nongnu.org --- hw/s390x/s390-virtio-hcall.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/hw/s390x/s390-virtio-hcall.c b/hw/s390x/s390-virtio-hcall.c index ee626493c6..0e328d806d 100644 --- a/hw/s390x/s390-virtio-hcall.c +++ b/hw/s390x/s390-virtio-hcall.c @@ -26,11 +26,14 @@ void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn) int s390_virtio_hypercall(CPUS390XState *env) { - s390_virtio_fn fn = s390_diag500_table[env->regs[1]]; + s390_virtio_fn fn; - if (!fn) { - return -EINVAL; + if (env->regs[1] < MAX_DIAG_SUBCODES) { + fn = s390_diag500_table[env->regs[1]]; + if (fn) { + return fn(&env->regs[2]); + } } - return fn(&env->regs[2]); + return -EINVAL; } From 77319f22635e3f0ef86730503b4d18dd9a833529 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 14 Jan 2014 13:32:23 +0100 Subject: [PATCH 06/22] s390x/virtio-hcall: Specification exception for illegal subcodes So far, the DIAG 500 hypervisor call was only setting -EINVAL in R2 when a guest tried to call this function with an illegal subcode. This patch now changes the behavior so that a specification exception is thrown instead, since this is the common behavior of other DIAG functions (and other CPU instructions) when being called with illegal parameters. Signed-off-by: Thomas Huth Reviewed-by: Cornelia Huck Signed-off-by: Christian Borntraeger --- hw/s390x/s390-virtio-hcall.c | 3 ++- target-s390x/kvm.c | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/hw/s390x/s390-virtio-hcall.c b/hw/s390x/s390-virtio-hcall.c index 0e328d806d..c7bdc2005d 100644 --- a/hw/s390x/s390-virtio-hcall.c +++ b/hw/s390x/s390-virtio-hcall.c @@ -31,7 +31,8 @@ int s390_virtio_hypercall(CPUS390XState *env) if (env->regs[1] < MAX_DIAG_SUBCODES) { fn = s390_diag500_table[env->regs[1]]; if (fn) { - return fn(&env->regs[2]); + env->regs[2] = fn(&env->regs[2]); + return 0; } } diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index b93fe84121..2fa374acc2 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -559,11 +559,16 @@ static int handle_priv(S390CPU *cpu, struct kvm_run *run, static int handle_hypercall(S390CPU *cpu, struct kvm_run *run) { CPUS390XState *env = &cpu->env; + int ret; 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) From 9da45bb217db41510684cbfd4e173186eb2f8477 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Fri, 7 Feb 2014 13:41:58 +0100 Subject: [PATCH 07/22] s390x/eventfacility: mask out commands As a followup to commit 5f04c14a10fa7f259bc0808f35a0beda49f7821e (s390-sclp: Define New SCLP Codes) we should mask the sclp command not only in base sclp, but also in the event facility. Based on an initial patch from Ralf Hoppe. Signed-off-by: Christian Borntraeger --- hw/s390x/event-facility.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index a73c0b924a..1e8c99ae94 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -299,7 +299,7 @@ static const TypeInfo s390_sclp_events_bus_info = { 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: read_event_data(ef, sccb); break; From a0fa2cb8ccf0b73cfd3ac01d557401a2303c0de4 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 13 Jan 2014 12:19:03 +0100 Subject: [PATCH 08/22] s390x/sclp: Fixed the size of sccb and code parameter The pointer to the SCCB should not be limited to 32 bits only. In contrast to this, the command word parameter is only 32 bits (the upper 32 bits should be ignored). Signed-off-by: Thomas Huth Reviewed-by: Cornelia Huck Signed-off-by: Christian Borntraeger --- hw/s390x/sclp.c | 4 ++-- target-s390x/cpu.h | 2 +- target-s390x/kvm.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index 4e0c564c5c..6134d4f904 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -89,7 +89,7 @@ static void sclp_read_cpu_info(SCCB *sccb) 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(); @@ -107,7 +107,7 @@ static void sclp_execute(SCCB *sccb, uint64_t code) } } -int sclp_service_call(uint32_t sccb, uint64_t code) +int sclp_service_call(uint64_t sccb, uint32_t code) { int r = 0; SCCB work_sccb; diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index b09ff92099..373c1151c1 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -963,7 +963,7 @@ struct sysib_322 { void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr); int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc, target_ulong *raddr, int *flags); -int sclp_service_call(uint32_t sccb, uint64_t code); +int sclp_service_call(uint64_t sccb, uint32_t code); uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, uint64_t vr); diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 2fa374acc2..9e1083e9d8 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -440,8 +440,8 @@ static int kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run, uint16_t ipbh0) { CPUS390XState *env = &cpu->env; - uint32_t sccb; - uint64_t code; + uint64_t sccb; + uint32_t code; int r = 0; cpu_synchronize_state(CPU(cpu)); From 6e25280216fc23c8387892f76d961559da124528 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 13 Jan 2014 12:55:55 +0100 Subject: [PATCH 09/22] s390x/sclp: Add missing checks to SCLP handler If the 51 most significant bits of the SCCB address are zero or equal to the prefix, we should throw an specification exception, too. Also moved the check for privileged mode to sclp_service_call() to have all program checks in one place now. Signed-off-by: Thomas Huth Reviewed-by: Cornelia Huck Signed-off-by: Christian Borntraeger --- hw/s390x/sclp.c | 9 +++++++-- target-s390x/cpu.h | 2 +- target-s390x/kvm.c | 6 +----- target-s390x/misc_helper.c | 2 +- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index 6134d4f904..98809777c8 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -107,7 +107,7 @@ static void sclp_execute(SCCB *sccb, uint32_t code) } } -int sclp_service_call(uint64_t sccb, uint32_t code) +int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code) { int r = 0; SCCB work_sccb; @@ -115,11 +115,16 @@ int sclp_service_call(uint64_t sccb, uint32_t code) hwaddr sccb_len = sizeof(SCCB); /* 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)) { r = -PGM_ADDRESSING; goto out; } - if (sccb & ~0x7ffffff8ul) { + if ((sccb & ~0x1fffUL) == 0 || (sccb & ~0x1fffUL) == env->psa + || (sccb & ~0x7ffffff8UL) != 0) { r = -PGM_SPECIFICATION; goto out; } diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 373c1151c1..96738384c7 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -963,7 +963,7 @@ struct sysib_322 { void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr); int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc, target_ulong *raddr, int *flags); -int sclp_service_call(uint64_t sccb, uint32_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, uint64_t vr); diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 9e1083e9d8..e7b3b1375c 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -445,14 +445,10 @@ static int kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run, int r = 0; cpu_synchronize_state(CPU(cpu)); - if (env->psw.mask & PSW_MASK_PSTATE) { - enter_pgmcheck(cpu, PGM_PRIVILEGED); - return 0; - } sccb = env->regs[ipbh0 & 0xf]; code = env->regs[(ipbh0 & 0xf0) >> 4]; - r = sclp_service_call(sccb, code); + r = sclp_service_call(env, sccb, code); if (r < 0) { enter_pgmcheck(cpu, -r); } diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 10d04252d5..728456f295 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -93,7 +93,7 @@ void program_interrupt(CPUS390XState *env, uint32_t code, int ilen) /* SCLP service call */ 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) { program_interrupt(env, -r, 4); return 0; From e8803d93df1bbaebe015b602a8178b424903bf5f Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 14 Jan 2014 12:13:32 +0100 Subject: [PATCH 10/22] s390x/sclp: Fixed setting of condition code register In the SCLP handler function, the condition code register must only be set if no exception occured. Signed-off-by: Thomas Huth Reviewed-by: Cornelia Huck Signed-off-by: Christian Borntraeger --- target-s390x/kvm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index e7b3b1375c..d3f0d4a7b2 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -451,8 +451,9 @@ static int kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run, r = sclp_service_call(env, sccb, code); if (r < 0) { enter_pgmcheck(cpu, -r); + } else { + setcc(cpu, r); } - setcc(cpu, r); return 0; } From 65e526c24e27863b2a0093e1350a8ae558be5936 Mon Sep 17 00:00:00 2001 From: Heinz Graalfs Date: Mon, 23 Dec 2013 10:25:38 +0100 Subject: [PATCH 11/22] s390x/event-facility: some renaming Do some renaming to shorten some identifiers and to emphasize sclp. Signed-off-by: Heinz Graalfs Acked-by: Cornelia Huck Signed-off-by: Christian Borntraeger --- hw/s390x/event-facility.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index 1e8c99ae94..e0ee7379e2 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -21,12 +21,12 @@ #include "hw/s390x/sclp.h" #include "hw/s390x/event-facility.h" -typedef struct EventTypesBus { +typedef struct SCLPEventsBus { BusState qbus; -} EventTypesBus; +} SCLPEventsBus; struct SCLPEventFacility { - EventTypesBus sbus; + SCLPEventsBus sbus; DeviceState *qdev; /* guest' 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, .parent = TYPE_BUS, .class_init = sclp_events_bus_class_init, @@ -360,7 +360,7 @@ static void init_event_facility_class(ObjectClass *klass, void *data) k->init = init_event_facility; } -static const TypeInfo s390_sclp_event_facility_info = { +static const TypeInfo sclp_event_facility_info = { .name = "s390-sclp-event-facility", .parent = TYPE_DEVICE_S390_SCLP, .instance_size = sizeof(S390SCLPDevice), @@ -395,7 +395,7 @@ static void event_class_init(ObjectClass *klass, void *data) dc->exit = event_qdev_exit; } -static const TypeInfo s390_sclp_event_type_info = { +static const TypeInfo sclp_event_type_info = { .name = TYPE_SCLP_EVENT, .parent = TYPE_DEVICE, .instance_size = sizeof(SCLPEvent), @@ -406,9 +406,9 @@ static const TypeInfo s390_sclp_event_type_info = { static void register_types(void) { - type_register_static(&s390_sclp_events_bus_info); - type_register_static(&s390_sclp_event_facility_info); - type_register_static(&s390_sclp_event_type_info); + type_register_static(&sclp_events_bus_info); + type_register_static(&sclp_event_facility_info); + type_register_static(&sclp_event_type_info); } type_init(register_types) From 477a72a1eff40639761e103f5b7652af7746c48e Mon Sep 17 00:00:00 2001 From: Heinz Graalfs Date: Wed, 18 Dec 2013 10:10:49 +0100 Subject: [PATCH 12/22] s390x/event-facility: code restructure Code restructure in order to simplify class hierarchy - remove S390SCLPDevice abstract base class and move function pointers into new SCLPEventFacilityClass - implement SCLPEventFacility as SysBusDevice - use define constants for instance creation strings The following ascii-art shows the class structure wrt the SCLP EventFacility before (CURRENT) and after the restructure (NEW): ---- CURRENT: "s390-sclp-events-bus" +-------------------------+ | SCLPEventsBus | |-------------------------| |BusState qbus | +-------------------------+ +-------------------------+ | SCLPEventFacility | - to be replaced by new SCLPEventFacility, |-------------------------| which will be a SysBusDevice |SCLPEventsBus sbus | |DeviceState *qdev | |unsigned int receive_mask| +-------------------------+ +-------------------------+ | S390SCLPDeviceClass | - to be replaced by new SCLPEventFacilityClass |-------------------------| |DeviceClass qdev | |*(init)() | +-------------------------+ "s390-sclp-event-facility" | instance-of | V "s390-sclp-device" - this is an abstract class +-------------------------+ | S390SCLPDevice (A)| - to be replaced by new SCLPEventFacility |-------------------------| |SysBusDevice busdev | |SCLPEventFacility *ef | | | |*(sclp_command_handler)()| - these 2 go to new SCLPEventFacilityClass |*(event_pending)() | +-------------------------+ ---- NEW: "s390-sclp-events-bus" +-------------------------+ | SCLPEventsBus | |-------------------------| |BusState qbus | +-------------------------+ +-------------------------+ | SCLPEventFacilityClass | |-------------------------| |DeviceClass parent_class | | | |*(init)() | |*(command_handler)() | |*(event_pending)() | +-------------------------+ "s390-sclp-event-facility" +-------------------------+ | SCLPEventFacility | |-------------------------| |SysBusDevice parent_class| |SCLPEventsBus sbus | |unsigned int receive_mask| +-------------------------+ Signed-off-by: Heinz Graalfs Reviewed-by: Cornelia Huck Signed-off-by: Christian Borntraeger --- hw/s390x/event-facility.c | 34 +++++++++--------- hw/s390x/sclp.c | 58 +++++++------------------------ include/hw/s390x/event-facility.h | 19 ++++++++++ include/hw/s390x/sclp.h | 24 ------------- 4 files changed, 47 insertions(+), 88 deletions(-) diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index e0ee7379e2..8ad2dc4094 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -26,8 +26,8 @@ typedef struct SCLPEventsBus { } SCLPEventsBus; struct SCLPEventFacility { + SysBusDevice parent_obj; SCLPEventsBus sbus; - DeviceState *qdev; /* guest' receive mask */ unsigned int receive_mask; }; @@ -315,21 +315,15 @@ static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code) } } -static int init_event_facility(S390SCLPDevice *sdev) +static int init_event_facility(SCLPEventFacility *event_facility) { - SCLPEventFacility *event_facility; + DeviceState *sdev = DEVICE(event_facility); DeviceState *quiesce; - event_facility = g_malloc0(sizeof(SCLPEventFacility)); - sdev->ef = event_facility; - sdev->sclp_command_handler = command_handler; - sdev->event_pending = event_pending; - - /* Spawn a new sclp-events facility */ + /* Spawn a new bus for SCLP events */ 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->qdev = (DeviceState *) sdev; quiesce = qdev_create(&event_facility->sbus.qbus, "sclpquiesce"); if (!quiesce) { @@ -346,25 +340,29 @@ static int init_event_facility(S390SCLPDevice *sdev) 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) { - DeviceClass *dc = DEVICE_CLASS(klass); - S390SCLPDeviceClass *k = SCLP_S390_DEVICE_CLASS(klass); + SysBusDeviceClass *sbdc = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(sbdc); + SCLPEventFacilityClass *k = EVENT_FACILITY_CLASS(dc); dc->reset = reset_event_facility; k->init = init_event_facility; + k->command_handler = command_handler; + k->event_pending = event_pending; } static const TypeInfo sclp_event_facility_info = { - .name = "s390-sclp-event-facility", - .parent = TYPE_DEVICE_S390_SCLP, - .instance_size = sizeof(S390SCLPDevice), + .name = TYPE_SCLP_EVENT_FACILITY, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SCLPEventFacility), .class_init = init_event_facility_class, + .class_size = sizeof(SCLPEventFacilityClass), }; static int event_qdev_init(DeviceState *qdev) diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index 98809777c8..d8ddf35e58 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -18,11 +18,12 @@ #include "sysemu/sysemu.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(), - "s390-sclp-event-facility", + TYPE_SCLP_EVENT_FACILITY, NULL); assert(op); return op->opaque; @@ -91,7 +92,8 @@ static void sclp_read_cpu_info(SCCB *sccb) 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) { case SCLP_CMDW_READ_SCP_INFO: @@ -102,7 +104,7 @@ static void sclp_execute(SCCB *sccb, uint32_t code) sclp_read_cpu_info(sccb); break; default: - sdev->sclp_command_handler(sdev->ef, sccb, code); + efc->command_handler(ef, sccb, code); break; } } @@ -156,11 +158,13 @@ out: 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; /* Indicate whether an event is still pending */ - param |= sdev->event_pending(sdev->ef) ? 1 : 0; + param |= efc->event_pending(ef) ? 1 : 0; if (!param) { /* No need to send an interrupt, there's nothing to be notified about */ @@ -173,47 +177,9 @@ void sclp_service_interrupt(uint32_t sccb) 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); 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) diff --git a/include/hw/s390x/event-facility.h b/include/hw/s390x/event-facility.h index 870edd46f6..6a062b668a 100644 --- a/include/hw/s390x/event-facility.h +++ b/include/hw/s390x/event-facility.h @@ -176,4 +176,23 @@ typedef struct SCLPEventClass { bool (*can_handle_event)(uint8_t type); } 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 diff --git a/include/hw/s390x/sclp.h b/include/hw/s390x/sclp.h index 35112d92b1..7ef16226df 100644 --- a/include/hw/s390x/sclp.h +++ b/include/hw/s390x/sclp.h @@ -161,30 +161,6 @@ static inline int sccb_data_len(SCCB *sccb) 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 sclp_service_interrupt(uint32_t sccb); From 6fbef18a4c8b3cd9c3da4772ed5ddaec9be06fac Mon Sep 17 00:00:00 2001 From: Heinz Graalfs Date: Wed, 18 Dec 2013 13:59:57 +0100 Subject: [PATCH 13/22] s390x/event-facility: add support for live migration Add support for live migration using VMStateDescription. Signed-off-by: Heinz Graalfs Reviewed-by: Cornelia Huck Signed-off-by: Christian Borntraeger --- hw/s390x/event-facility.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index 8ad2dc4094..5b6d5c65b5 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -315,6 +315,17 @@ static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code) } } +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) { DeviceState *sdev = DEVICE(event_facility); @@ -352,6 +363,7 @@ static void init_event_facility_class(ObjectClass *klass, void *data) SCLPEventFacilityClass *k = EVENT_FACILITY_CLASS(dc); dc->reset = reset_event_facility; + dc->vmsd = &vmstate_event_facility; k->init = init_event_facility; k->command_handler = command_handler; k->event_pending = event_pending; From c804c2a71752dd1e150cde768d8c54b02fa8bad9 Mon Sep 17 00:00:00 2001 From: Heinz Graalfs Date: Fri, 20 Dec 2013 12:02:17 +0100 Subject: [PATCH 14/22] s390x/event-facility: exploit realize/unrealize init/exit functionality of abstract SCLPEvent class is now exploiting realize/unrealize. Signed-off-by: Heinz Graalfs Reviewed-by: Cornelia Huck Signed-off-by: Christian Borntraeger --- hw/s390x/event-facility.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index 5b6d5c65b5..0777a93916 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -377,22 +377,31 @@ static const TypeInfo sclp_event_facility_info = { .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); - 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); 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) @@ -401,8 +410,8 @@ static void event_class_init(ObjectClass *klass, void *data) dc->bus_type = TYPE_SCLP_EVENTS_BUS; dc->unplug = qdev_simple_unplug_cb; - dc->init = event_qdev_init; - dc->exit = event_qdev_exit; + dc->realize = event_realize; + dc->unrealize = event_unrealize; } static const TypeInfo sclp_event_type_info = { From d1028f1b5b4cf83e8af5f48996cf392fb12d391a Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Wed, 12 Feb 2014 16:17:35 +0100 Subject: [PATCH 15/22] s390-ccw.img: Fix sporadic reboot hangs: Initialize next_idx The current code does not initialize next_idx in the virtio ring. As the ccw bios will always use guest memory at a fixed location, this queue might != 0 after a reboot. Lets make the initialization explicit. Signed-off-by: Christian Borntraeger Reviewed-by: Cornelia Huck --- pc-bios/s390-ccw/virtio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c index 4d6e48fcbe..a46914dd68 100644 --- a/pc-bios/s390-ccw/virtio.c +++ b/pc-bios/s390-ccw/virtio.c @@ -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->idx = 0; vr->used_idx = 0; + vr->next_idx = 0; debug_print_addr("init vr", vr); } From 5d739a4787a53da8d787551c8de27ad39fabdb34 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Tue, 11 Feb 2014 22:46:53 +0100 Subject: [PATCH 16/22] s390-ccw.img: Fix sporadic errors with ccw boot image - initialize css We have to set the cssid to 0, otherwise the stsch code will return an operand exception without the m bit. In the same way we should set m=0. This case was triggered in some cases during reboot, if for some reason the location of blk_schid.cssid contains 1 and m was 0. Turns out that the qemu elf loader does not zero out the bss section on reboot. The symptom was an dump of the old kernel with several areas overwritten. The bootloader does not register a program check handler, so bios exception jumped back into the old kernel. Lets just use a local struct with a designed initializer. That will guarantee that all other subelements are initialized to 0. Signed-off-by: Christian Borntraeger Reviewed-by: Cornelia Huck --- pc-bios/s390-ccw/main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c index c5d533231b..5c33766533 100644 --- a/pc-bios/s390-ccw/main.c +++ b/pc-bios/s390-ccw/main.c @@ -10,7 +10,6 @@ #include "s390-ccw.h" -struct subchannel_id blk_schid; char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE))); uint64_t boot_value; @@ -23,13 +22,13 @@ void virtio_panic(const char *string) static void virtio_setup(uint64_t dev_info) { + struct subchannel_id blk_schid = { .one = 1 }; struct schib schib; int i; int r; bool found = false; bool check_devno = false; uint16_t dev_no = -1; - blk_schid.one = 1; if (dev_info != -1) { check_devno = true; From 0ca3611221d8d80bcf98337f4691addc07df0b08 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Thu, 13 Feb 2014 09:48:12 +0100 Subject: [PATCH 17/22] s390-ccw.img: new binary rom to match latest fixes Signed-off-by: Christian Borntraeger --- pc-bios/s390-ccw.img | Bin 9336 -> 9336 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img index 6727f0ca39d6bf6d114974d1535cb7ad9e56355f..f6223e77c2aacfa86652d63b773dc05eca55570d 100644 GIT binary patch delta 1460 zcmYLJeN0{B598rap=*kQJ&?u}Igs0Y|(CEtrhk^vfveG`nf| zQG1G)0|AjT-{nR@TC54+G%-KBC7IeZ9IiLDU=L1enL5eI)&qGZdM~>Z@|zm}mik19 zMYN89O$5EdEu=%RH9ZNSkK!+iUFt?mvas+p^L~g}-C|c%#E}wznw?OFy>5HZ>wvMm z8`Hka10~Ly0q)#HXG7Hk0rhwoVEyVg>Qw+M+!8TLd+ik@mtL?J)G>e+8pft>2o9~BoN#Ewl^K@@5k zO}HoPwmc1n zf_f`Bt2*^;;^!3`Sg{lyDv1;u76Q@&mntm^*>x!DF|m3|SkKT-hu3iidmfi%BZ$0T zFqkd9fNG9La*-}M{FbyOn(nM5Gql?IIJq?bsw@+%ems%$UX)1_OmP98D8_6QIx&3Y#hhc*4`6;6f=WFrKHh?lcxqgM#y5F%e27E}=aI+pfF)$eW zyBASI)DTU^?yq9@D#reqN5n_D>PHMCP9Y+1Z71SY#7V?e#@2`N_NZ6`UT{kgtE@sq z{>DB;yzrYNh;xjkteDt_Irwk_&{~g|%+pqnFD-zPx@g$ras_k3(iQ_}3;-RBB}eIb zPaQGnJx@(x2igv7GXOle-aye&y3gw)Wwg~>PC~TTTUm_q;3hN;WDMFYKTO@&-h&T` z3}ZQ6^p>}V1Zj3rsI(@--1>Uhq*46BKMFoP-E^*0`wtZv7?}V7 delta 1362 zcmYLIZA@EL7=BN0;TBlP?Z-;n_2U*;z`%sX1sJH{Ky0#U2+mlHKdOm_#APxi1kE!1 zKt;!N-I*DSm^9k%GBaZXnm9G&M(45wWHoG&7>y*C{V>IFmvz`p?D0Kk3!dcmdGEQ; z`@GL{?rlDjj~ow?+PK&R z*&+QJ0GW*{G0;`qT}%0Z^x&P*r~+8EcE+?(IFPLZ1-7Kz?3U-{{b~l@Rl)9daGs_> zu{H?LXcIuRuK^xPm`QDnvD6SiY5@pW_Ozuc@U98KQ|oq)@V4n)37D<~bxZ}nb}vXc z#2F{%S;R8OY5a8iAS zh+XL|!CJ;=NwA5&SrPRGeJ^kNNXr3e!QSCT$bBqYJ`^HWS{ZE3D1b)q3`)}P>~%ZpjP!92SUFGfqUInpqeYp8473Q=^ADL%z+YJ>tR-y2^=y^%F3v+jcVa$^JKZ~>|ddjZK z8PFBVh3B%DuiL33nf9Zl7Xs#WZsqEpU*^AsMoAso$kqih(}pY9MR$plb*Dd1lg8L&(GQ!q!j84chNMimaU5Ad7UV z;sNp%b$i0(GHvm6mc1DP^9)yee1*R4IYukIL9$MpymjsT3m9dq+yU9n!)z289oK8| zGx~xjkaOaR#Gm|=M{lp-%l^achiW~89buaA2FNs>^|r}*JThBZ_=K;MFxur)-MR_3 z-c|l*>iyFghyheoI*4i`x}8YBCa6zGnTJK zd=2pmBJyrEB3?qAN6a&JdlEkm54ubv_F#?{MC5ODAx<#%FX~#B7%Sj#2`{l+0Q87I zKvw9aKU6e^O087)yWPFzdCOf2!2MVqU@VuWtNwO!iPi_2y@R;7XOjWo$9jXY^#nZ} z2$6a^8K@yKdLhsdMtiUT-A7BtZI+AkbDKT8aM($VbC|k<%_K_q1sisvbtv6rh{+Zg zMoc32S?GSRl&c(*-!J~4=;`t$i)Edj3)Y~cE5U}MJoX)&iIX`?*oq}41L={+o&f1w z=P!lRTid?<@%f?ozScKl!3d>ahO;;_QQ1y9=yK(YCDA)WeNh^%YA)e6aBWM|3B1E| M Date: Wed, 12 Feb 2014 09:56:35 +0100 Subject: [PATCH 18/22] s390x/cpu: Use ioctl to reset state in the kernel Some of the state in the kernel can not be reset from QEMU yet. For this we've got to use the KVM_S390_INITIAL_RESET ioctl to make sure that the state in the kernel is set to the right values during initial CPU reset, too. Signed-off-by: Thomas Huth Acked-by: Cornelia Huck Signed-off-by: Christian Borntraeger --- target-s390x/cpu.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index f1319e55a6..1a8c1cc39f 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -108,6 +108,15 @@ static void s390_cpu_initial_reset(CPUState *s) 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() */ From f7d3e466764e0258d0883d90edb7e98ad0b56e18 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 24 Jan 2014 16:39:54 +0100 Subject: [PATCH 19/22] s390x/kvm: Rework SIGP INITIAL CPU RESET handler The s390_cpu_initial_reset() function had two deficiencies: First, it used an ioctl for the destination CPU, and this ioctl could block nearly forever, as long as the destination CPU was running in the SIE loop. Second, it also cleared the general purpose registers - something it should not do according to the Principles of Operations. Since we've already got another function for the initial CPU reset in cpu.c, we can also use that function instead. And by using run_on_cpu() for executing this code, we make sure that the destination CPU is correctly kicked out of kernel mode now. Suggested-by: Christian Borntraeger Signed-off-by: Thomas Huth Reviewed-by: Cornelia Huck Signed-off-by: Christian Borntraeger --- target-s390x/kvm.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index d3f0d4a7b2..75e88224e3 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -626,25 +626,13 @@ int kvm_s390_cpu_restart(S390CPU *cpu) return 0; } -static int s390_cpu_initial_reset(S390CPU *cpu) +static void sigp_initial_cpu_reset(void *arg) { - CPUState *cs = CPU(cpu); - CPUS390XState *env = &cpu->env; - int i; + CPUState *cpu = arg; + S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); - s390_del_running_cpu(cpu); - if (kvm_vcpu_ioctl(cs, KVM_S390_INITIAL_RESET, NULL) < 0) { - perror("cannot init reset vcpu"); - } - - /* Manually zero out all registers */ - cpu_synchronize_state(cs); - for (i = 0; i < 16; i++) { - env->regs[i] = 0; - } - - DPRINTF("DONE: SIGP initial reset: %p\n", env); - return 0; + cpu_synchronize_state(cpu); + scc->initial_cpu_reset(cpu); } #define SIGP_ORDER_MASK 0x000000ff @@ -683,7 +671,8 @@ static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) cc = 1; /* status stored */ break; 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; default: DPRINTF("KVM: unknown SIGP: 0x%x\n", order_code); From 04c2b5168e242e6fa6901442bd399aa7087effca Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 24 Jan 2014 17:18:38 +0100 Subject: [PATCH 20/22] s390x/kvm: Add missing SIGP CPU RESET order The SIGP order CPU RESET was still missing in the list of our supported handler. This patch now adds a simple implementation, by using the cpu_reset() function that is already available in target-s390x/cpu.c. Signed-off-by: Thomas Huth Reviewed-by: Christian Borntraeger Reviewed-by: Cornelia Huck Signed-off-by: Christian Borntraeger --- target-s390x/kvm.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 75e88224e3..20c711fd2c 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -635,6 +635,15 @@ static void sigp_initial_cpu_reset(void *arg) scc->initial_cpu_reset(cpu); } +static void sigp_cpu_reset(void *arg) +{ + CPUState *cpu = arg; + S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); + + cpu_synchronize_state(cpu); + scc->cpu_reset(cpu); +} + #define SIGP_ORDER_MASK 0x000000ff static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) @@ -674,6 +683,10 @@ static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) 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; default: DPRINTF("KVM: unknown SIGP: 0x%x\n", order_code); *statusreg &= 0xffffffff00000000UL; From 1eecf41b3e8128979dd571f63d0b4c7fedc919c2 Mon Sep 17 00:00:00 2001 From: Frank Blaschka Date: Tue, 11 Feb 2014 08:41:38 +0100 Subject: [PATCH 21/22] s390x/kvm: Rework priv instruction handlers The current implementation uses the second byte of the instruction to identify the instruction handler. This is not sufficient to support instructions not starting with 0xb2. This patch adds separate handlers for 0xb2, 0xb9 and 0xeb to be able to support the full instruction set. Signed-off-by: Frank Blaschka Reviewed-by: Cornelia Huck Reviewed-by: Christian Borntraeger Signed-off-by: Christian Borntraeger --- target-s390x/kvm.c | 139 ++++++++++++++++++++++++++------------------- 1 file changed, 80 insertions(+), 59 deletions(-) diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 20c711fd2c..11feda9eb9 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -53,25 +53,28 @@ #define IPA0_B9 0xb900 #define IPA0_EB 0xeb00 -#define PRIV_SCLP_CALL 0x20 -#define PRIV_CSCH 0x30 -#define PRIV_HSCH 0x31 -#define PRIV_MSCH 0x32 -#define PRIV_SSCH 0x33 -#define PRIV_STSCH 0x34 -#define PRIV_TSCH 0x35 -#define PRIV_TPI 0x36 -#define PRIV_SAL 0x37 -#define PRIV_RSCH 0x38 -#define PRIV_STCRW 0x39 -#define PRIV_STCPS 0x3a -#define PRIV_RCHP 0x3b -#define PRIV_SCHM 0x3c -#define PRIV_CHSC 0x5f -#define PRIV_SIGA 0x74 -#define PRIV_XSCH 0x76 -#define PRIV_SQBS 0x8a -#define PRIV_EQBS 0x9c +#define PRIV_B2_SCLP_CALL 0x20 +#define PRIV_B2_CSCH 0x30 +#define PRIV_B2_HSCH 0x31 +#define PRIV_B2_MSCH 0x32 +#define PRIV_B2_SSCH 0x33 +#define PRIV_B2_STSCH 0x34 +#define PRIV_B2_TSCH 0x35 +#define PRIV_B2_TPI 0x36 +#define PRIV_B2_SAL 0x37 +#define PRIV_B2_RSCH 0x38 +#define PRIV_B2_STCRW 0x39 +#define PRIV_B2_STCPS 0x3a +#define PRIV_B2_RCHP 0x3b +#define PRIV_B2_SCHM 0x3c +#define PRIV_B2_CHSC 0x5f +#define PRIV_B2_SIGA 0x74 +#define PRIV_B2_XSCH 0x76 + +#define PRIV_EB_SQBS 0x8a + +#define PRIV_B9_EQBS 0x9c + #define DIAG_IPL 0x308 #define DIAG_KVM_HYPERCALL 0x500 #define DIAG_KVM_BREAKPOINT 0x501 @@ -458,96 +461,110 @@ static int kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run, return 0; } -static int kvm_handle_css_inst(S390CPU *cpu, struct kvm_run *run, - uint8_t ipa0, uint8_t ipa1, uint8_t ipb) +static int handle_b2(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) { CPUS390XState *env = &cpu->env; - - if (ipa0 != 0xb2) { - /* Not handled for now. */ - return -1; - } + int rc = 0; + uint16_t ipbh0 = (run->s390_sieic.ipb & 0xffff0000) >> 16; cpu_synchronize_state(CPU(cpu)); switch (ipa1) { - case PRIV_XSCH: + case PRIV_B2_XSCH: ioinst_handle_xsch(cpu, env->regs[1]); break; - case PRIV_CSCH: + case PRIV_B2_CSCH: ioinst_handle_csch(cpu, env->regs[1]); break; - case PRIV_HSCH: + case PRIV_B2_HSCH: ioinst_handle_hsch(cpu, env->regs[1]); break; - case PRIV_MSCH: + case PRIV_B2_MSCH: ioinst_handle_msch(cpu, env->regs[1], run->s390_sieic.ipb); break; - case PRIV_SSCH: + case PRIV_B2_SSCH: ioinst_handle_ssch(cpu, env->regs[1], run->s390_sieic.ipb); break; - case PRIV_STCRW: + case PRIV_B2_STCRW: ioinst_handle_stcrw(cpu, run->s390_sieic.ipb); break; - case PRIV_STSCH: + case PRIV_B2_STSCH: ioinst_handle_stsch(cpu, env->regs[1], run->s390_sieic.ipb); break; - case PRIV_TSCH: + case PRIV_B2_TSCH: /* We should only get tsch via KVM_EXIT_S390_TSCH. */ fprintf(stderr, "Spurious tsch intercept\n"); break; - case PRIV_CHSC: + case PRIV_B2_CHSC: ioinst_handle_chsc(cpu, run->s390_sieic.ipb); break; - case PRIV_TPI: + case PRIV_B2_TPI: /* This should have been handled by kvm already. */ fprintf(stderr, "Spurious tpi intercept\n"); break; - case PRIV_SCHM: + case PRIV_B2_SCHM: ioinst_handle_schm(cpu, env->regs[1], env->regs[2], run->s390_sieic.ipb); break; - case PRIV_RSCH: + case PRIV_B2_RSCH: ioinst_handle_rsch(cpu, env->regs[1]); break; - case PRIV_RCHP: + case PRIV_B2_RCHP: ioinst_handle_rchp(cpu, env->regs[1]); break; - case PRIV_STCPS: + case PRIV_B2_STCPS: /* We do not provide this instruction, it is suppressed. */ break; - case PRIV_SAL: + case PRIV_B2_SAL: ioinst_handle_sal(cpu, env->regs[1]); break; - case PRIV_SIGA: + case PRIV_B2_SIGA: /* Not provided, set CC = 3 for subchannel not operational */ setcc(cpu, 3); break; + case PRIV_B2_SCLP_CALL: + rc = kvm_sclp_service_call(cpu, run, ipbh0); + break; 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, - uint8_t ipa0, uint8_t ipa1) +static int handle_b9(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) { 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) { - case PRIV_SCLP_CALL: - r = kvm_sclp_service_call(cpu, run, ipbh0); - break; - default: - r = kvm_handle_css_inst(cpu, run, ipa0, ipa1, ipb); - if (r == -1) { - DPRINTF("KVM: unhandled PRIV: 0x%x\n", ipa1); - } - break; + case PRIV_B9_EQBS: + /* just inject exception */ + r = -1; + break; + default: + r = -1; + DPRINTF("KVM: unhandled PRIV: 0xb9%x\n", ipa1); + 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; @@ -710,9 +727,13 @@ static void handle_instruction(S390CPU *cpu, struct kvm_run *run) run->s390_sieic.ipa, run->s390_sieic.ipb); switch (ipa0) { case IPA0_B2: + r = handle_b2(cpu, run, ipa1); + break; case IPA0_B9: + r = handle_b9(cpu, run, ipa1); + break; case IPA0_EB: - r = handle_priv(cpu, run, ipa0 >> 8, ipa1); + r = handle_eb(cpu, run, ipa1); break; case IPA0_DIAG: r = handle_diag(cpu, run, run->s390_sieic.ipb); From 7f00eb30febf1054c74b163ced984afcdbf6e670 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Sat, 8 Feb 2014 12:31:15 +0100 Subject: [PATCH 22/22] s390x/ipl: Fix crash of ELF images with arbitrary entry points When loading S390 kernels, the current code expects an ELF file with the start address 0x10000. Other ELF files cause a segmentation fault. To avoid these crashes, we should get the start address from the ELF file instead of always using a hard-coded address. Signed-off-by: Thomas Huth Acked-by: Cornelia Huck Signed-off-by: Christian Borntraeger --- hw/s390x/ipl.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index 1a6397b88e..04fb1a8e05 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -95,7 +95,8 @@ static int s390_ipl_init(SysBusDevice *dev) } return 0; } 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); if (kernel_size == -1) { 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); 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 - * value was 0x800 (the SALIPL loader) and it wont work. For - * all (Linux) cases 0x10000 (KERN_IMAGE_START) should be fine. + * Is it a Linux kernel (starting at 0x10000)? If yes, we fill in the + * kernel parameters here as well. Note: For old kernels (up to 3.2) + * 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) { ram_addr_t initrd_offset;