Sfoglia il codice sorgente

Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20141010' into staging

various s390x updates:
- cpu state handling in qemu and migration
- vhost-scsi-ccw bugfix

# gpg: Signature made Fri 10 Oct 2014 14:01:34 BST using RSA key ID C6F02FAF
# gpg: Can't check signature: public key not found

* remotes/cohuck/tags/s390x-20141010:
  s390x/virtio-ccw: fix vhost-scsi intialization
  s390x/migration: migrate CPU state
  s390x/kvm: synchronize the cpu state after SIGP (INITIAL) CPU RESET
  s390x/kvm: reuse kvm_s390_reset_vcpu() to get rid of ifdefs
  s390x/kvm: propagate s390 cpu state to kvm
  s390x/kvm: proper use of the cpu states OPERATING and STOPPED
  s390x/kvm: introduce proper states for s390 cpus
  linux-headers: update to 3.17-rc7

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Peter Maydell 11 anni fa
parent
commit
b1d28ec6a7

+ 1 - 1
hw/s390x/ipl.c

@@ -176,7 +176,7 @@ static void s390_ipl_reset(DeviceState *dev)
         }
         }
     }
     }
 
 
-    s390_add_running_cpu(cpu);
+    s390_cpu_set_state(CPU_STATE_OPERATING, cpu);
 }
 }
 
 
 static void s390_ipl_class_init(ObjectClass *klass, void *data)
 static void s390_ipl_class_init(ObjectClass *klass, void *data)

+ 0 - 32
hw/s390x/s390-virtio.c

@@ -125,38 +125,6 @@ static void s390_virtio_register_hcalls(void)
                                    s390_virtio_hcall_set_status);
                                    s390_virtio_hcall_set_status);
 }
 }
 
 
-/*
- * The number of running CPUs. On s390 a shutdown is the state of all CPUs
- * being either stopped or disabled (for interrupts) waiting. We have to
- * track this number to call the shutdown sequence accordingly. This
- * number is modified either on startup or while holding the big qemu lock.
- */
-static unsigned s390_running_cpus;
-
-void s390_add_running_cpu(S390CPU *cpu)
-{
-    CPUState *cs = CPU(cpu);
-
-    if (cs->halted) {
-        s390_running_cpus++;
-        cs->halted = 0;
-        cs->exception_index = -1;
-    }
-}
-
-unsigned s390_del_running_cpu(S390CPU *cpu)
-{
-    CPUState *cs = CPU(cpu);
-
-    if (cs->halted == 0) {
-        assert(s390_running_cpus >= 1);
-        s390_running_cpus--;
-        cs->halted = 1;
-        cs->exception_index = EXCP_HLT;
-    }
-    return s390_running_cpus;
-}
-
 void s390_init_ipl_dev(const char *kernel_filename,
 void s390_init_ipl_dev(const char *kernel_filename,
                        const char *kernel_cmdline,
                        const char *kernel_cmdline,
                        const char *initrd_filename,
                        const char *initrd_filename,

+ 1 - 1
hw/s390x/virtio-ccw.c

@@ -1528,7 +1528,7 @@ static void vhost_ccw_scsi_class_init(ObjectClass *klass, void *data)
 static const TypeInfo vhost_ccw_scsi = {
 static const TypeInfo vhost_ccw_scsi = {
     .name          = TYPE_VHOST_SCSI_CCW,
     .name          = TYPE_VHOST_SCSI_CCW,
     .parent        = TYPE_VIRTIO_CCW_DEVICE,
     .parent        = TYPE_VIRTIO_CCW_DEVICE,
-    .instance_size = sizeof(VirtIOSCSICcw),
+    .instance_size = sizeof(VHostSCSICcw),
     .instance_init = vhost_ccw_scsi_instance_init,
     .instance_init = vhost_ccw_scsi_instance_init,
     .class_init    = vhost_ccw_scsi_class_init,
     .class_init    = vhost_ccw_scsi_class_init,
 };
 };

+ 5 - 1
linux-headers/asm-mips/kvm_para.h

@@ -1 +1,5 @@
-#include <asm-generic/kvm_para.h>
+#ifndef _ASM_MIPS_KVM_PARA_H
+#define _ASM_MIPS_KVM_PARA_H
+
+
+#endif /* _ASM_MIPS_KVM_PARA_H */

+ 2 - 0
linux-headers/asm-powerpc/kvm.h

@@ -548,6 +548,7 @@ struct kvm_get_htab_header {
 
 
 #define KVM_REG_PPC_VRSAVE	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 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)
 #define KVM_REG_PPC_LPCR	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb5)
+#define KVM_REG_PPC_LPCR_64	(KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb5)
 #define KVM_REG_PPC_PPR		(KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb6)
 #define KVM_REG_PPC_PPR		(KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb6)
 
 
 /* Architecture compatibility level */
 /* Architecture compatibility level */
@@ -555,6 +556,7 @@ struct kvm_get_htab_header {
 
 
 #define KVM_REG_PPC_DABRX	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb8)
 #define KVM_REG_PPC_DABRX	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb8)
 #define KVM_REG_PPC_WORT	(KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb9)
 #define KVM_REG_PPC_WORT	(KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb9)
+#define KVM_REG_PPC_SPRG9	(KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xba)
 
 
 /* Transactional Memory checkpointed state:
 /* Transactional Memory checkpointed state:
  * This is all GPRs, all VSX regs and a subset of SPRs
  * This is all GPRs, all VSX regs and a subset of SPRs

+ 3 - 0
linux-headers/asm-x86/kvm.h

@@ -23,7 +23,10 @@
 #define GP_VECTOR 13
 #define GP_VECTOR 13
 #define PF_VECTOR 14
 #define PF_VECTOR 14
 #define MF_VECTOR 16
 #define MF_VECTOR 16
+#define AC_VECTOR 17
 #define MC_VECTOR 18
 #define MC_VECTOR 18
+#define XM_VECTOR 19
+#define VE_VECTOR 20
 
 
 /* Select x86 specific features in <linux/kvm.h> */
 /* Select x86 specific features in <linux/kvm.h> */
 #define __KVM_HAVE_PIT
 #define __KVM_HAVE_PIT

+ 10 - 3
linux-headers/linux/kvm.h

@@ -162,7 +162,7 @@ struct kvm_pit_config {
 #define KVM_EXIT_TPR_ACCESS       12
 #define KVM_EXIT_TPR_ACCESS       12
 #define KVM_EXIT_S390_SIEIC       13
 #define KVM_EXIT_S390_SIEIC       13
 #define KVM_EXIT_S390_RESET       14
 #define KVM_EXIT_S390_RESET       14
-#define KVM_EXIT_DCR              15
+#define KVM_EXIT_DCR              15 /* deprecated */
 #define KVM_EXIT_NMI              16
 #define KVM_EXIT_NMI              16
 #define KVM_EXIT_INTERNAL_ERROR   17
 #define KVM_EXIT_INTERNAL_ERROR   17
 #define KVM_EXIT_OSI              18
 #define KVM_EXIT_OSI              18
@@ -268,7 +268,7 @@ struct kvm_run {
 			__u64 trans_exc_code;
 			__u64 trans_exc_code;
 			__u32 pgm_code;
 			__u32 pgm_code;
 		} s390_ucontrol;
 		} s390_ucontrol;
-		/* KVM_EXIT_DCR */
+		/* KVM_EXIT_DCR (deprecated) */
 		struct {
 		struct {
 			__u32 dcrn;
 			__u32 dcrn;
 			__u32 data;
 			__u32 data;
@@ -399,13 +399,18 @@ struct kvm_vapic_addr {
 	__u64 vapic_addr;
 	__u64 vapic_addr;
 };
 };
 
 
-/* for KVM_SET_MPSTATE */
+/* for KVM_SET_MP_STATE */
 
 
+/* not all states are valid on all architectures */
 #define KVM_MP_STATE_RUNNABLE          0
 #define KVM_MP_STATE_RUNNABLE          0
 #define KVM_MP_STATE_UNINITIALIZED     1
 #define KVM_MP_STATE_UNINITIALIZED     1
 #define KVM_MP_STATE_INIT_RECEIVED     2
 #define KVM_MP_STATE_INIT_RECEIVED     2
 #define KVM_MP_STATE_HALTED            3
 #define KVM_MP_STATE_HALTED            3
 #define KVM_MP_STATE_SIPI_RECEIVED     4
 #define KVM_MP_STATE_SIPI_RECEIVED     4
+#define KVM_MP_STATE_STOPPED           5
+#define KVM_MP_STATE_CHECK_STOP        6
+#define KVM_MP_STATE_OPERATING         7
+#define KVM_MP_STATE_LOAD              8
 
 
 struct kvm_mp_state {
 struct kvm_mp_state {
 	__u32 mp_state;
 	__u32 mp_state;
@@ -758,6 +763,8 @@ struct kvm_ppc_smmu_info {
 #define KVM_CAP_VM_ATTRIBUTES 101
 #define KVM_CAP_VM_ATTRIBUTES 101
 #define KVM_CAP_ARM_PSCI_0_2 102
 #define KVM_CAP_ARM_PSCI_0_2 102
 #define KVM_CAP_PPC_FIXUP_HCALL 103
 #define KVM_CAP_PPC_FIXUP_HCALL 103
+#define KVM_CAP_PPC_ENABLE_HCALL 104
+#define KVM_CAP_CHECK_EXTENSION_VM 105
 
 
 #ifdef KVM_CAP_IRQ_ROUTING
 #ifdef KVM_CAP_IRQ_ROUTING
 
 

+ 3 - 0
linux-headers/linux/kvm_para.h

@@ -20,6 +20,9 @@
 #define KVM_HC_FEATURES			3
 #define KVM_HC_FEATURES			3
 #define KVM_HC_PPC_MAP_MAGIC_PAGE	4
 #define KVM_HC_PPC_MAP_MAGIC_PAGE	4
 #define KVM_HC_KICK_CPU			5
 #define KVM_HC_KICK_CPU			5
+#define KVM_HC_MIPS_GET_CLOCK_FREQ	6
+#define KVM_HC_MIPS_EXIT_VM		7
+#define KVM_HC_MIPS_CONSOLE_OUTPUT	8
 
 
 /*
 /*
  * hypercalls use architecture specific
  * hypercalls use architecture specific

+ 34 - 0
linux-headers/linux/vfio.h

@@ -30,6 +30,9 @@
  */
  */
 #define VFIO_DMA_CC_IOMMU		4
 #define VFIO_DMA_CC_IOMMU		4
 
 
+/* Check if EEH is supported */
+#define VFIO_EEH			5
+
 /*
 /*
  * The IOCTL interface is designed for extensibility by embedding the
  * The IOCTL interface is designed for extensibility by embedding the
  * structure length (argsz) and flags into structures passed between
  * structure length (argsz) and flags into structures passed between
@@ -455,6 +458,37 @@ struct vfio_iommu_spapr_tce_info {
 
 
 #define VFIO_IOMMU_SPAPR_TCE_GET_INFO	_IO(VFIO_TYPE, VFIO_BASE + 12)
 #define VFIO_IOMMU_SPAPR_TCE_GET_INFO	_IO(VFIO_TYPE, VFIO_BASE + 12)
 
 
+/*
+ * EEH PE operation struct provides ways to:
+ * - enable/disable EEH functionality;
+ * - unfreeze IO/DMA for frozen PE;
+ * - read PE state;
+ * - reset PE;
+ * - configure PE.
+ */
+struct vfio_eeh_pe_op {
+	__u32 argsz;
+	__u32 flags;
+	__u32 op;
+};
+
+#define VFIO_EEH_PE_DISABLE		0	/* Disable EEH functionality */
+#define VFIO_EEH_PE_ENABLE		1	/* Enable EEH functionality  */
+#define VFIO_EEH_PE_UNFREEZE_IO		2	/* Enable IO for frozen PE   */
+#define VFIO_EEH_PE_UNFREEZE_DMA	3	/* Enable DMA for frozen PE  */
+#define VFIO_EEH_PE_GET_STATE		4	/* PE state retrieval        */
+#define  VFIO_EEH_PE_STATE_NORMAL	0	/* PE in functional state    */
+#define  VFIO_EEH_PE_STATE_RESET	1	/* PE reset in progress      */
+#define  VFIO_EEH_PE_STATE_STOPPED	2	/* Stopped DMA and IO        */
+#define  VFIO_EEH_PE_STATE_STOPPED_DMA	4	/* Stopped DMA only          */
+#define  VFIO_EEH_PE_STATE_UNAVAIL	5	/* State unavailable         */
+#define VFIO_EEH_PE_RESET_DEACTIVATE	5	/* Deassert PE reset         */
+#define VFIO_EEH_PE_RESET_HOT		6	/* Assert hot reset          */
+#define VFIO_EEH_PE_RESET_FUNDAMENTAL	7	/* Assert fundamental reset  */
+#define VFIO_EEH_PE_CONFIGURE		8	/* PE configuration          */
+
+#define VFIO_EEH_PE_OP			_IO(VFIO_TYPE, VFIO_BASE + 21)
+
 /* ***************************************************************** */
 /* ***************************************************************** */
 
 
 #endif /* VFIO_H */
 #endif /* VFIO_H */

+ 1 - 1
linux-headers/linux/vhost.h

@@ -14,7 +14,7 @@
 
 
 #include <linux/ioctl.h>
 #include <linux/ioctl.h>
 #include <linux/virtio_config.h>
 #include <linux/virtio_config.h>
-#include "hw/virtio/virtio_ring.h"
+#include <linux/virtio_ring.h>
 
 
 struct vhost_vring_state {
 struct vhost_vring_state {
 	unsigned int index;
 	unsigned int index;

+ 1 - 1
target-s390x/Makefile.objs

@@ -1,5 +1,5 @@
 obj-y += translate.o helper.o cpu.o interrupt.o
 obj-y += translate.o helper.o cpu.o interrupt.o
 obj-y += int_helper.o fpu_helper.o cc_helper.o mem_helper.o misc_helper.o
 obj-y += int_helper.o fpu_helper.o cc_helper.o mem_helper.o misc_helper.o
 obj-y += gdbstub.o
 obj-y += gdbstub.o
-obj-$(CONFIG_SOFTMMU) += ioinst.o arch_dump.o
+obj-$(CONFIG_SOFTMMU) += machine.o ioinst.o arch_dump.o
 obj-$(CONFIG_KVM) += kvm.o
 obj-$(CONFIG_KVM) += kvm.o

+ 4 - 0
target-s390x/cpu-qom.h

@@ -77,6 +77,10 @@ static inline S390CPU *s390_env_get_cpu(CPUS390XState *env)
 
 
 #define ENV_OFFSET offsetof(S390CPU, env)
 #define ENV_OFFSET offsetof(S390CPU, env)
 
 
+#ifndef CONFIG_USER_ONLY
+extern const struct VMStateDescription vmstate_s390_cpu;
+#endif
+
 void s390_cpu_do_interrupt(CPUState *cpu);
 void s390_cpu_do_interrupt(CPUState *cpu);
 bool s390_cpu_exec_interrupt(CPUState *cpu, int int_req);
 bool s390_cpu_exec_interrupt(CPUState *cpu, int int_req);
 void s390_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
 void s390_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,

+ 86 - 28
target-s390x/cpu.c

@@ -26,7 +26,9 @@
 #include "cpu.h"
 #include "cpu.h"
 #include "qemu-common.h"
 #include "qemu-common.h"
 #include "qemu/timer.h"
 #include "qemu/timer.h"
+#include "qemu/error-report.h"
 #include "hw/hw.h"
 #include "hw/hw.h"
+#include "trace.h"
 #ifndef CONFIG_USER_ONLY
 #ifndef CONFIG_USER_ONLY
 #include "sysemu/arch_init.h"
 #include "sysemu/arch_init.h"
 #endif
 #endif
@@ -81,7 +83,7 @@ static void s390_cpu_load_normal(CPUState *s)
     S390CPU *cpu = S390_CPU(s);
     S390CPU *cpu = S390_CPU(s);
     cpu->env.psw.addr = ldl_phys(s->as, 4) & PSW_MASK_ESA_ADDR;
     cpu->env.psw.addr = ldl_phys(s->as, 4) & PSW_MASK_ESA_ADDR;
     cpu->env.psw.mask = PSW_MASK_32 | PSW_MASK_64;
     cpu->env.psw.mask = PSW_MASK_32 | PSW_MASK_64;
-    s390_add_running_cpu(cpu);
+    s390_cpu_set_state(CPU_STATE_OPERATING, cpu);
 }
 }
 #endif
 #endif
 
 
@@ -93,11 +95,8 @@ static void s390_cpu_reset(CPUState *s)
     CPUS390XState *env = &cpu->env;
     CPUS390XState *env = &cpu->env;
 
 
     env->pfault_token = -1UL;
     env->pfault_token = -1UL;
-    s390_del_running_cpu(cpu);
     scc->parent_reset(s);
     scc->parent_reset(s);
-#if !defined(CONFIG_USER_ONLY)
-    s->halted = 1;
-#endif
+    s390_cpu_set_state(CPU_STATE_STOPPED, cpu);
     tlb_flush(s, 1);
     tlb_flush(s, 1);
 }
 }
 
 
@@ -118,14 +117,10 @@ static void s390_cpu_initial_reset(CPUState *s)
 
 
     env->pfault_token = -1UL;
     env->pfault_token = -1UL;
 
 
-#if defined(CONFIG_KVM)
     /* Reset state inside the kernel that we cannot access yet from QEMU. */
     /* Reset state inside the kernel that we cannot access yet from QEMU. */
     if (kvm_enabled()) {
     if (kvm_enabled()) {
-        if (kvm_vcpu_ioctl(s, KVM_S390_INITIAL_RESET, NULL)) {
-            perror("Initial CPU reset failed");
-        }
+        kvm_s390_reset_vcpu(cpu);
     }
     }
-#endif
 }
 }
 
 
 /* CPUClass:reset() */
 /* CPUClass:reset() */
@@ -135,9 +130,8 @@ static void s390_cpu_full_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;
 
 
-    s390_del_running_cpu(cpu);
-
     scc->parent_reset(s);
     scc->parent_reset(s);
+    s390_cpu_set_state(CPU_STATE_STOPPED, cpu);
 
 
     memset(env, 0, offsetof(CPUS390XState, cpu_num));
     memset(env, 0, offsetof(CPUS390XState, cpu_num));
 
 
@@ -147,16 +141,10 @@ static void s390_cpu_full_reset(CPUState *s)
 
 
     env->pfault_token = -1UL;
     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 */
-#if !defined(CONFIG_USER_ONLY)
-    s->halted = 1;
-
+    /* Reset state inside the kernel that we cannot access yet from QEMU. */
     if (kvm_enabled()) {
     if (kvm_enabled()) {
         kvm_s390_reset_vcpu(cpu);
         kvm_s390_reset_vcpu(cpu);
     }
     }
-#endif
     tlb_flush(s, 1);
     tlb_flush(s, 1);
 }
 }
 
 
@@ -206,10 +194,7 @@ static void s390_cpu_initfn(Object *obj)
     env->tod_basetime = 0;
     env->tod_basetime = 0;
     env->tod_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_tod_timer, cpu);
     env->tod_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_tod_timer, cpu);
     env->cpu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_cpu_timer, cpu);
     env->cpu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_cpu_timer, cpu);
-    /* set CPUState::halted state to 1 to avoid decrementing the running
-     * cpu counter in s390_cpu_reset to a negative number at
-     * initial ipl */
-    cs->halted = 1;
+    s390_cpu_set_state(CPU_STATE_STOPPED, cpu);
 #endif
 #endif
     env->cpu_num = cpu_num++;
     env->cpu_num = cpu_num++;
     env->ext_index = -1;
     env->ext_index = -1;
@@ -229,10 +214,83 @@ static void s390_cpu_finalize(Object *obj)
 #endif
 #endif
 }
 }
 
 
-static const VMStateDescription vmstate_s390_cpu = {
-    .name = "cpu",
-    .unmigratable = 1,
-};
+#if !defined(CONFIG_USER_ONLY)
+static bool disabled_wait(CPUState *cpu)
+{
+    return cpu->halted && !(S390_CPU(cpu)->env.psw.mask &
+                            (PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK));
+}
+
+static unsigned s390_count_running_cpus(void)
+{
+    CPUState *cpu;
+    int nr_running = 0;
+
+    CPU_FOREACH(cpu) {
+        uint8_t state = S390_CPU(cpu)->env.cpu_state;
+        if (state == CPU_STATE_OPERATING ||
+            state == CPU_STATE_LOAD) {
+            if (!disabled_wait(cpu)) {
+                nr_running++;
+            }
+        }
+    }
+
+    return nr_running;
+}
+
+unsigned int s390_cpu_halt(S390CPU *cpu)
+{
+    CPUState *cs = CPU(cpu);
+    trace_cpu_halt(cs->cpu_index);
+
+    if (!cs->halted) {
+        cs->halted = 1;
+        cs->exception_index = EXCP_HLT;
+    }
+
+    return s390_count_running_cpus();
+}
+
+void s390_cpu_unhalt(S390CPU *cpu)
+{
+    CPUState *cs = CPU(cpu);
+    trace_cpu_unhalt(cs->cpu_index);
+
+    if (cs->halted) {
+        cs->halted = 0;
+        cs->exception_index = -1;
+    }
+}
+
+unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu)
+ {
+    trace_cpu_set_state(CPU(cpu)->cpu_index, cpu_state);
+
+    switch (cpu_state) {
+    case CPU_STATE_STOPPED:
+    case CPU_STATE_CHECK_STOP:
+        /* halt the cpu for common infrastructure */
+        s390_cpu_halt(cpu);
+        break;
+    case CPU_STATE_OPERATING:
+    case CPU_STATE_LOAD:
+        /* unhalt the cpu for common infrastructure */
+        s390_cpu_unhalt(cpu);
+        break;
+    default:
+        error_report("Requested CPU state is not a valid S390 CPU state: %u",
+                     cpu_state);
+        exit(1);
+    }
+    if (kvm_enabled() && cpu->env.cpu_state != cpu_state) {
+        kvm_s390_set_cpu_state(cpu, cpu_state);
+    }
+    cpu->env.cpu_state = cpu_state;
+
+    return s390_count_running_cpus();
+}
+#endif
 
 
 static void s390_cpu_class_init(ObjectClass *oc, void *data)
 static void s390_cpu_class_init(ObjectClass *oc, void *data)
 {
 {
@@ -260,11 +318,11 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data)
     cc->handle_mmu_fault = s390_cpu_handle_mmu_fault;
     cc->handle_mmu_fault = s390_cpu_handle_mmu_fault;
 #else
 #else
     cc->get_phys_page_debug = s390_cpu_get_phys_page_debug;
     cc->get_phys_page_debug = s390_cpu_get_phys_page_debug;
+    cc->vmsd = &vmstate_s390_cpu;
     cc->write_elf64_note = s390_cpu_write_elf64_note;
     cc->write_elf64_note = s390_cpu_write_elf64_note;
     cc->write_elf64_qemunote = s390_cpu_write_elf64_qemunote;
     cc->write_elf64_qemunote = s390_cpu_write_elf64_qemunote;
     cc->cpu_exec_interrupt = s390_cpu_exec_interrupt;
     cc->cpu_exec_interrupt = s390_cpu_exec_interrupt;
 #endif
 #endif
-    dc->vmsd = &vmstate_s390_cpu;
     cc->gdb_num_core_regs = S390_NUM_CORE_REGS;
     cc->gdb_num_core_regs = S390_NUM_CORE_REGS;
     cc->gdb_core_xml_file = "s390x-core64.xml";
     cc->gdb_core_xml_file = "s390x-core64.xml";
 }
 }

+ 33 - 8
target-s390x/cpu.h

@@ -141,6 +141,20 @@ typedef struct CPUS390XState {
     QEMUTimer *tod_timer;
     QEMUTimer *tod_timer;
 
 
     QEMUTimer *cpu_timer;
     QEMUTimer *cpu_timer;
+
+    /*
+     * The cpu state represents the logical state of a cpu. In contrast to other
+     * architectures, there is a difference between a halt and a stop on s390.
+     * If all cpus are either stopped (including check stop) or in the disabled
+     * wait state, the vm can be shut down.
+     */
+#define CPU_STATE_UNINITIALIZED        0x00
+#define CPU_STATE_STOPPED              0x01
+#define CPU_STATE_CHECK_STOP           0x02
+#define CPU_STATE_OPERATING            0x03
+#define CPU_STATE_LOAD                 0x04
+    uint8_t cpu_state;
+
 } CPUS390XState;
 } CPUS390XState;
 
 
 #include "cpu-qom.h"
 #include "cpu-qom.h"
@@ -375,16 +389,12 @@ int s390_virtio_hypercall(CPUS390XState *env);
 void s390_virtio_irq(int config_change, uint64_t token);
 void s390_virtio_irq(int config_change, uint64_t token);
 
 
 #ifdef CONFIG_KVM
 #ifdef CONFIG_KVM
-void kvm_s390_reset_vcpu(S390CPU *cpu);
 void kvm_s390_virtio_irq(int config_change, uint64_t token);
 void kvm_s390_virtio_irq(int config_change, uint64_t token);
 void kvm_s390_service_interrupt(uint32_t parm);
 void kvm_s390_service_interrupt(uint32_t parm);
 void kvm_s390_vcpu_interrupt(S390CPU *cpu, struct kvm_s390_irq *irq);
 void kvm_s390_vcpu_interrupt(S390CPU *cpu, struct kvm_s390_irq *irq);
 void kvm_s390_floating_interrupt(struct kvm_s390_irq *irq);
 void kvm_s390_floating_interrupt(struct kvm_s390_irq *irq);
 int kvm_s390_inject_flic(struct kvm_s390_irq *irq);
 int kvm_s390_inject_flic(struct kvm_s390_irq *irq);
 #else
 #else
-static inline void kvm_s390_reset_vcpu(S390CPU *cpu)
-{
-}
 static inline void kvm_s390_virtio_irq(int config_change, uint64_t token)
 static inline void kvm_s390_virtio_irq(int config_change, uint64_t token)
 {
 {
 }
 }
@@ -393,8 +403,9 @@ static inline void kvm_s390_service_interrupt(uint32_t parm)
 }
 }
 #endif
 #endif
 S390CPU *s390_cpu_addr2state(uint16_t cpu_addr);
 S390CPU *s390_cpu_addr2state(uint16_t cpu_addr);
-void s390_add_running_cpu(S390CPU *cpu);
-unsigned s390_del_running_cpu(S390CPU *cpu);
+unsigned int s390_cpu_halt(S390CPU *cpu);
+void s390_cpu_unhalt(S390CPU *cpu);
+unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu);
 
 
 /* service interrupts are floating therefore we must not pass an cpustate */
 /* service interrupts are floating therefore we must not pass an cpustate */
 void s390_sclp_extint(uint32_t parm);
 void s390_sclp_extint(uint32_t parm);
@@ -403,11 +414,16 @@ void s390_sclp_extint(uint32_t parm);
 extern const hwaddr virtio_size;
 extern const hwaddr virtio_size;
 
 
 #else
 #else
-static inline void s390_add_running_cpu(S390CPU *cpu)
+static inline unsigned int s390_cpu_halt(S390CPU *cpu)
 {
 {
+    return 0;
 }
 }
 
 
-static inline unsigned s390_del_running_cpu(S390CPU *cpu)
+static inline void s390_cpu_unhalt(S390CPU *cpu)
+{
+}
+
+static inline unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu)
 {
 {
     return 0;
     return 0;
 }
 }
@@ -1052,6 +1068,8 @@ int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch,
 int kvm_s390_cpu_restart(S390CPU *cpu);
 int kvm_s390_cpu_restart(S390CPU *cpu);
 int kvm_s390_get_memslot_count(KVMState *s);
 int kvm_s390_get_memslot_count(KVMState *s);
 void kvm_s390_clear_cmma_callback(void *opaque);
 void kvm_s390_clear_cmma_callback(void *opaque);
+int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state);
+void kvm_s390_reset_vcpu(S390CPU *cpu);
 #else
 #else
 static inline void kvm_s390_io_interrupt(uint16_t subchannel_id,
 static inline void kvm_s390_io_interrupt(uint16_t subchannel_id,
                                         uint16_t subchannel_nr,
                                         uint16_t subchannel_nr,
@@ -1082,6 +1100,13 @@ static inline int kvm_s390_get_memslot_count(KVMState *s)
 {
 {
   return MAX_AVAIL_SLOTS;
   return MAX_AVAIL_SLOTS;
 }
 }
+static inline int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state)
+{
+    return -ENOSYS;
+}
+static inline void kvm_s390_reset_vcpu(S390CPU *cpu)
+{
+}
 #endif
 #endif
 
 
 static inline void cmma_reset(S390CPU *cpu)
 static inline void cmma_reset(S390CPU *cpu)

+ 7 - 12
target-s390x/helper.c

@@ -504,23 +504,18 @@ hwaddr s390_cpu_get_phys_addr_debug(CPUState *cs, vaddr vaddr)
 
 
 void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
 void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
 {
 {
+    env->psw.addr = addr;
+    env->psw.mask = mask;
+    env->cc_op = (mask >> 44) & 3;
+
     if (mask & PSW_MASK_WAIT) {
     if (mask & PSW_MASK_WAIT) {
         S390CPU *cpu = s390_env_get_cpu(env);
         S390CPU *cpu = s390_env_get_cpu(env);
-        CPUState *cs = CPU(cpu);
-        if (!(mask & (PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK))) {
-            if (s390_del_running_cpu(cpu) == 0) {
+        if (s390_cpu_halt(cpu) == 0) {
 #ifndef CONFIG_USER_ONLY
 #ifndef CONFIG_USER_ONLY
-                qemu_system_shutdown_request();
+            qemu_system_shutdown_request();
 #endif
 #endif
-            }
         }
         }
-        cs->halted = 1;
-        cs->exception_index = EXCP_HLT;
     }
     }
-
-    env->psw.addr = addr;
-    env->psw.mask = mask;
-    env->cc_op = (mask >> 44) & 3;
 }
 }
 
 
 static uint64_t get_psw_mask(CPUS390XState *env)
 static uint64_t get_psw_mask(CPUS390XState *env)
@@ -818,7 +813,7 @@ void s390_cpu_do_interrupt(CPUState *cs)
     qemu_log_mask(CPU_LOG_INT, "%s: %d at pc=%" PRIx64 "\n",
     qemu_log_mask(CPU_LOG_INT, "%s: %d at pc=%" PRIx64 "\n",
                   __func__, cs->exception_index, env->psw.addr);
                   __func__, cs->exception_index, env->psw.addr);
 
 
-    s390_add_running_cpu(cpu);
+    s390_cpu_set_state(CPU_STATE_OPERATING, cpu);
     /* handle machine checks */
     /* handle machine checks */
     if ((env->psw.mask & PSW_MASK_MCHECK) &&
     if ((env->psw.mask & PSW_MASK_MCHECK) &&
         (cs->exception_index == -1)) {
         (cs->exception_index == -1)) {

+ 50 - 8
target-s390x/kvm.c

@@ -181,9 +181,10 @@ unsigned long kvm_arch_vcpu_id(CPUState *cpu)
     return cpu->cpu_index;
     return cpu->cpu_index;
 }
 }
 
 
-int kvm_arch_init_vcpu(CPUState *cpu)
+int kvm_arch_init_vcpu(CPUState *cs)
 {
 {
-    /* nothing todo yet */
+    S390CPU *cpu = S390_CPU(cs);
+    kvm_s390_set_cpu_state(cpu, cpu->env.cpu_state);
     return 0;
     return 0;
 }
 }
 
 
@@ -197,7 +198,7 @@ void kvm_s390_reset_vcpu(S390CPU *cpu)
      * Before this ioctl cpu_synchronize_state() is called in common kvm
      * Before this ioctl cpu_synchronize_state() is called in common kvm
      * code (kvm-all) */
      * code (kvm-all) */
     if (kvm_vcpu_ioctl(cs, KVM_S390_INITIAL_RESET, NULL)) {
     if (kvm_vcpu_ioctl(cs, KVM_S390_INITIAL_RESET, NULL)) {
-        perror("Can't reset vcpu\n");
+        error_report("Initial CPU reset failed on CPU %i\n", cs->cpu_index);
     }
     }
 }
 }
 
 
@@ -921,7 +922,7 @@ static void sigp_cpu_start(void *arg)
     CPUState *cs = arg;
     CPUState *cs = arg;
     S390CPU *cpu = S390_CPU(cs);
     S390CPU *cpu = S390_CPU(cs);
 
 
-    s390_add_running_cpu(cpu);
+    s390_cpu_set_state(CPU_STATE_OPERATING, cpu);
     DPRINTF("DONE: KVM cpu start: %p\n", &cpu->env);
     DPRINTF("DONE: KVM cpu start: %p\n", &cpu->env);
 }
 }
 
 
@@ -934,7 +935,7 @@ static void sigp_cpu_restart(void *arg)
     };
     };
 
 
     kvm_s390_vcpu_interrupt(cpu, &irq);
     kvm_s390_vcpu_interrupt(cpu, &irq);
-    s390_add_running_cpu(cpu);
+    s390_cpu_set_state(CPU_STATE_OPERATING, cpu);
 }
 }
 
 
 int kvm_s390_cpu_restart(S390CPU *cpu)
 int kvm_s390_cpu_restart(S390CPU *cpu)
@@ -951,6 +952,7 @@ static void sigp_initial_cpu_reset(void *arg)
 
 
     cpu_synchronize_state(cpu);
     cpu_synchronize_state(cpu);
     scc->initial_cpu_reset(cpu);
     scc->initial_cpu_reset(cpu);
+    cpu_synchronize_post_reset(cpu);
 }
 }
 
 
 static void sigp_cpu_reset(void *arg)
 static void sigp_cpu_reset(void *arg)
@@ -960,6 +962,7 @@ static void sigp_cpu_reset(void *arg)
 
 
     cpu_synchronize_state(cpu);
     cpu_synchronize_state(cpu);
     scc->cpu_reset(cpu);
     scc->cpu_reset(cpu);
+    cpu_synchronize_post_reset(cpu);
 }
 }
 
 
 #define SIGP_ORDER_MASK 0x000000ff
 #define SIGP_ORDER_MASK 0x000000ff
@@ -1074,7 +1077,7 @@ static void unmanageable_intercept(S390CPU *cpu, const char *str, int pswoffset)
     error_report("Unmanageable %s! CPU%i new PSW: 0x%016lx:%016lx",
     error_report("Unmanageable %s! CPU%i new PSW: 0x%016lx:%016lx",
                  str, cs->cpu_index, ldq_phys(cs->as, cpu->env.psa + pswoffset),
                  str, cs->cpu_index, ldq_phys(cs->as, cpu->env.psa + pswoffset),
                  ldq_phys(cs->as, cpu->env.psa + pswoffset + 8));
                  ldq_phys(cs->as, cpu->env.psa + pswoffset + 8));
-    s390_del_running_cpu(cpu);
+    s390_cpu_halt(cpu);
     guest_panicked();
     guest_panicked();
 }
 }
 
 
@@ -1103,7 +1106,8 @@ static int handle_intercept(S390CPU *cpu)
             break;
             break;
         case ICPT_WAITPSW:
         case ICPT_WAITPSW:
             /* disabled wait, since enabled wait is handled in kernel */
             /* disabled wait, since enabled wait is handled in kernel */
-            if (s390_del_running_cpu(cpu) == 0) {
+            cpu_synchronize_state(cs);
+            if (s390_cpu_halt(cpu) == 0) {
                 if (is_special_wait_psw(cs)) {
                 if (is_special_wait_psw(cs)) {
                     qemu_system_shutdown_request();
                     qemu_system_shutdown_request();
                 } else {
                 } else {
@@ -1113,7 +1117,7 @@ static int handle_intercept(S390CPU *cpu)
             r = EXCP_HALTED;
             r = EXCP_HALTED;
             break;
             break;
         case ICPT_CPU_STOP:
         case ICPT_CPU_STOP:
-            if (s390_del_running_cpu(cpu) == 0) {
+            if (s390_cpu_set_state(CPU_STATE_STOPPED, cpu) == 0) {
                 qemu_system_shutdown_request();
                 qemu_system_shutdown_request();
             }
             }
             r = EXCP_HALTED;
             r = EXCP_HALTED;
@@ -1320,3 +1324,41 @@ int kvm_s390_get_memslot_count(KVMState *s)
 {
 {
     return kvm_check_extension(s, KVM_CAP_NR_MEMSLOTS);
     return kvm_check_extension(s, KVM_CAP_NR_MEMSLOTS);
 }
 }
+
+int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state)
+{
+    struct kvm_mp_state mp_state = {};
+    int ret;
+
+    /* the kvm part might not have been initialized yet */
+    if (CPU(cpu)->kvm_state == NULL) {
+        return 0;
+    }
+
+    switch (cpu_state) {
+    case CPU_STATE_STOPPED:
+        mp_state.mp_state = KVM_MP_STATE_STOPPED;
+        break;
+    case CPU_STATE_CHECK_STOP:
+        mp_state.mp_state = KVM_MP_STATE_CHECK_STOP;
+        break;
+    case CPU_STATE_OPERATING:
+        mp_state.mp_state = KVM_MP_STATE_OPERATING;
+        break;
+    case CPU_STATE_LOAD:
+        mp_state.mp_state = KVM_MP_STATE_LOAD;
+        break;
+    default:
+        error_report("Requested CPU state is not a valid S390 CPU state: %u",
+                     cpu_state);
+        exit(1);
+    }
+
+    ret = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MP_STATE, &mp_state);
+    if (ret) {
+        trace_kvm_failed_cpu_state_set(CPU(cpu)->cpu_index, cpu_state,
+                                       strerror(-ret));
+    }
+
+    return ret;
+}

+ 76 - 0
target-s390x/machine.c

@@ -0,0 +1,76 @@
+/*
+ * S390x machine definitions and functions
+ *
+ * Copyright IBM Corp. 2014
+ *
+ * Authors:
+ *   Thomas Huth <thuth@linux.vnet.ibm.com>
+ *   Christian Borntraeger <borntraeger@de.ibm.com>
+ *   Jason J. Herne <jjherne@us.ibm.com>
+ *
+ * This work is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License,
+ * or (at your option) any later version.
+ */
+
+#include "hw/hw.h"
+#include "cpu.h"
+#include "sysemu/kvm.h"
+
+static int cpu_post_load(void *opaque, int version_id)
+{
+    S390CPU *cpu = opaque;
+
+    /*
+     * As the cpu state is pushed to kvm via kvm_set_mp_state rather
+     * than via cpu_synchronize_state, we need update kvm here.
+     */
+    if (kvm_enabled()) {
+        kvm_s390_set_cpu_state(cpu, cpu->env.cpu_state);
+    }
+
+    return 0;
+}
+
+const VMStateDescription vmstate_s390_cpu = {
+    .name = "cpu",
+    .post_load = cpu_post_load,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT64(env.fregs[0].ll, S390CPU),
+        VMSTATE_UINT64(env.fregs[1].ll, S390CPU),
+        VMSTATE_UINT64(env.fregs[2].ll, S390CPU),
+        VMSTATE_UINT64(env.fregs[3].ll, S390CPU),
+        VMSTATE_UINT64(env.fregs[4].ll, S390CPU),
+        VMSTATE_UINT64(env.fregs[5].ll, S390CPU),
+        VMSTATE_UINT64(env.fregs[6].ll, S390CPU),
+        VMSTATE_UINT64(env.fregs[7].ll, S390CPU),
+        VMSTATE_UINT64(env.fregs[8].ll, S390CPU),
+        VMSTATE_UINT64(env.fregs[9].ll, S390CPU),
+        VMSTATE_UINT64(env.fregs[10].ll, S390CPU),
+        VMSTATE_UINT64(env.fregs[11].ll, S390CPU),
+        VMSTATE_UINT64(env.fregs[12].ll, S390CPU),
+        VMSTATE_UINT64(env.fregs[13].ll, S390CPU),
+        VMSTATE_UINT64(env.fregs[14].ll, S390CPU),
+        VMSTATE_UINT64(env.fregs[15].ll, S390CPU),
+        VMSTATE_UINT64_ARRAY(env.regs, S390CPU, 16),
+        VMSTATE_UINT64(env.psw.mask, S390CPU),
+        VMSTATE_UINT64(env.psw.addr, S390CPU),
+        VMSTATE_UINT64(env.psa, S390CPU),
+        VMSTATE_UINT32(env.fpc, S390CPU),
+        VMSTATE_UINT32(env.todpr, S390CPU),
+        VMSTATE_UINT64(env.pfault_token, S390CPU),
+        VMSTATE_UINT64(env.pfault_compare, S390CPU),
+        VMSTATE_UINT64(env.pfault_select, S390CPU),
+        VMSTATE_UINT64(env.cputm, S390CPU),
+        VMSTATE_UINT64(env.ckc, S390CPU),
+        VMSTATE_UINT64(env.gbea, S390CPU),
+        VMSTATE_UINT64(env.pp, S390CPU),
+        VMSTATE_UINT32_ARRAY(env.aregs, S390CPU, 16),
+        VMSTATE_UINT64_ARRAY(env.cregs, S390CPU, 16),
+        VMSTATE_UINT8(env.cpu_state, S390CPU),
+        VMSTATE_END_OF_LIST()
+     },
+};

+ 6 - 0
trace-events

@@ -1369,6 +1369,12 @@ mhp_pc_dimm_assigned_address(uint64_t addr) "0x%"PRIx64
 # target-s390x/kvm.c
 # target-s390x/kvm.c
 kvm_enable_cmma(int rc) "CMMA: enabling with result code %d"
 kvm_enable_cmma(int rc) "CMMA: enabling with result code %d"
 kvm_clear_cmma(int rc) "CMMA: clearing with result code %d"
 kvm_clear_cmma(int rc) "CMMA: clearing with result code %d"
+kvm_failed_cpu_state_set(int cpu_index, uint8_t state, const char *msg) "Warning: Unable to set cpu %d state %" PRIu8 " to KVM: %s"
 
 
 # hw/dma/i8257.c
 # hw/dma/i8257.c
 i8257_unregistered_dma(int nchan, int dma_pos, int dma_len) "unregistered DMA channel used nchan=%d dma_pos=%d dma_len=%d"
 i8257_unregistered_dma(int nchan, int dma_pos, int dma_len) "unregistered DMA channel used nchan=%d dma_pos=%d dma_len=%d"
+
+# target-s390x/cpu.c
+cpu_set_state(int cpu_index, uint8_t state) "setting cpu %d state to %" PRIu8
+cpu_halt(int cpu_index) "halting cpu %d"
+cpu_unhalt(int cpu_index) "unhalting cpu %d"