From a9fd16544dd3cdc50902ff652e2f57982f113497 Mon Sep 17 00:00:00 2001 From: Jens Freimann Date: Tue, 30 Sep 2014 10:57:27 +0200 Subject: [PATCH 1/8] linux-headers: update to 3.17-rc7 Sync headers with 3.17-rc7 Acked-by: Paolo Bonzini Signed-off-by: Jens Freimann Signed-off-by: Cornelia Huck --- linux-headers/asm-mips/kvm_para.h | 6 +++++- linux-headers/asm-powerpc/kvm.h | 2 ++ linux-headers/asm-x86/kvm.h | 3 +++ linux-headers/linux/kvm.h | 13 +++++++++--- linux-headers/linux/kvm_para.h | 3 +++ linux-headers/linux/vfio.h | 34 +++++++++++++++++++++++++++++++ linux-headers/linux/vhost.h | 2 +- 7 files changed, 58 insertions(+), 5 deletions(-) diff --git a/linux-headers/asm-mips/kvm_para.h b/linux-headers/asm-mips/kvm_para.h index 14fab8f0b9..dbb2464f3b 100644 --- a/linux-headers/asm-mips/kvm_para.h +++ b/linux-headers/asm-mips/kvm_para.h @@ -1 +1,5 @@ -#include +#ifndef _ASM_MIPS_KVM_PARA_H +#define _ASM_MIPS_KVM_PARA_H + + +#endif /* _ASM_MIPS_KVM_PARA_H */ diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h index 2bc4a9409a..e0e49dbb14 100644 --- a/linux-headers/asm-powerpc/kvm.h +++ b/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_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) /* 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_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: * This is all GPRs, all VSX regs and a subset of SPRs diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h index d3a87780c7..d7dcef58ae 100644 --- a/linux-headers/asm-x86/kvm.h +++ b/linux-headers/asm-x86/kvm.h @@ -23,7 +23,10 @@ #define GP_VECTOR 13 #define PF_VECTOR 14 #define MF_VECTOR 16 +#define AC_VECTOR 17 #define MC_VECTOR 18 +#define XM_VECTOR 19 +#define VE_VECTOR 20 /* Select x86 specific features in */ #define __KVM_HAVE_PIT diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index f5d2c38ded..266993879e 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -162,7 +162,7 @@ struct kvm_pit_config { #define KVM_EXIT_TPR_ACCESS 12 #define KVM_EXIT_S390_SIEIC 13 #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_INTERNAL_ERROR 17 #define KVM_EXIT_OSI 18 @@ -268,7 +268,7 @@ struct kvm_run { __u64 trans_exc_code; __u32 pgm_code; } s390_ucontrol; - /* KVM_EXIT_DCR */ + /* KVM_EXIT_DCR (deprecated) */ struct { __u32 dcrn; __u32 data; @@ -399,13 +399,18 @@ struct kvm_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_UNINITIALIZED 1 #define KVM_MP_STATE_INIT_RECEIVED 2 #define KVM_MP_STATE_HALTED 3 #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 { __u32 mp_state; @@ -758,6 +763,8 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_VM_ATTRIBUTES 101 #define KVM_CAP_ARM_PSCI_0_2 102 #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 diff --git a/linux-headers/linux/kvm_para.h b/linux-headers/linux/kvm_para.h index 2dff7838b4..e61661edf3 100644 --- a/linux-headers/linux/kvm_para.h +++ b/linux-headers/linux/kvm_para.h @@ -20,6 +20,9 @@ #define KVM_HC_FEATURES 3 #define KVM_HC_PPC_MAP_MAGIC_PAGE 4 #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 diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h index 26c218e692..95b591b61a 100644 --- a/linux-headers/linux/vfio.h +++ b/linux-headers/linux/vfio.h @@ -30,6 +30,9 @@ */ #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 * 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) +/* + * 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 */ diff --git a/linux-headers/linux/vhost.h b/linux-headers/linux/vhost.h index bb5df43874..c656f61cfc 100644 --- a/linux-headers/linux/vhost.h +++ b/linux-headers/linux/vhost.h @@ -14,7 +14,7 @@ #include #include -#include "hw/virtio/virtio_ring.h" +#include struct vhost_vring_state { unsigned int index; From 75973bfe415774babe7c1e18fa682c050fdce73b Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 30 Sep 2014 10:57:28 +0200 Subject: [PATCH 2/8] s390x/kvm: introduce proper states for s390 cpus Until now, when a s390 cpu was stopped or halted, the number of running CPUs was tracked in a global variable. This was problematic for migration, so Jason came up with a per-cpu running state. As it turns out, we want to track the full logical state of a target vcpu, so we need real s390 cpu states. This patch is based on an initial patch by Jason Herne, but was heavily rewritten when adding the cpu states STOPPED and OPERATING. On the way we move add_del_running to cpu.c (the declaration is already in cpu.h) and modify the users where appropriate. Please note that the cpu is still set to be stopped when it is halted, which is wrong. This will be fixed in the next patch. The LOAD and CHECK-STOP state will not be used in the first step. Signed-off-by: David Hildenbrand [folded Jason's patch into David's patch to avoid add/remove same lines] Signed-off-by: Jens Freimann Reviewed-by: Cornelia Huck Reviewed-by: Christian Borntraeger CC: Andreas Faerber Tested-by: Christian Borntraeger Signed-off-by: Cornelia Huck --- hw/s390x/s390-virtio.c | 32 ------------------------------- target-s390x/cpu.c | 43 ++++++++++++++++++++++++++++++++++++++++++ target-s390x/cpu.h | 14 ++++++++++++++ 3 files changed, 57 insertions(+), 32 deletions(-) diff --git a/hw/s390x/s390-virtio.c b/hw/s390x/s390-virtio.c index 9c61246375..af0004a0ac 100644 --- a/hw/s390x/s390-virtio.c +++ b/hw/s390x/s390-virtio.c @@ -125,38 +125,6 @@ static void s390_virtio_register_hcalls(void) 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, const char *kernel_cmdline, const char *initrd_filename, diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index 2cfeb829a1..03cab74181 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -229,6 +229,49 @@ static void s390_cpu_finalize(Object *obj) #endif } +#if !defined(CONFIG_USER_ONLY) +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) { + nr_running++; + } + } + + return nr_running; +} + +void s390_add_running_cpu(S390CPU *cpu) +{ + CPUState *cs = CPU(cpu); + + if (cs->halted) { + cpu->env.cpu_state = CPU_STATE_OPERATING; + cs->halted = 0; + cs->exception_index = -1; + } +} + +unsigned s390_del_running_cpu(S390CPU *cpu) +{ + CPUState *cs = CPU(cpu); + + if (cs->halted == 0) { + assert(s390_count_running_cpus() >= 1); + cpu->env.cpu_state = CPU_STATE_STOPPED; + cs->halted = 1; + cs->exception_index = EXCP_HLT; + } + + return s390_count_running_cpus(); +} +#endif + static const VMStateDescription vmstate_s390_cpu = { .name = "cpu", .unmigratable = 1, diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 62940c398a..f1a3ad263b 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -141,6 +141,20 @@ typedef struct CPUS390XState { QEMUTimer *tod_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; #include "cpu-qom.h" From eb24f7c6896e93047f2c58ffd3ba4f453e88280b Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 30 Sep 2014 10:57:29 +0200 Subject: [PATCH 3/8] s390x/kvm: proper use of the cpu states OPERATING and STOPPED This patch makes sure that halting a cpu and stopping a cpu are two different things. Stopping a cpu will also set the cpu halted - this is needed for common infrastructure to work (note that the stop and stopped flag cannot be used for our purpose because they are already used by other mechanisms). A cpu can be halted ("waiting") when it is operating. If interrupts are disabled, this is called a "disabled wait", as it can't be woken up anymore. A stopped cpu is treated like a "disabled wait" cpu, but in order to prepare for a proper cpu state synchronization with the kvm part, we need to track the real logical state of a cpu. Signed-off-by: David Hildenbrand Signed-off-by: Jens Freimann Reviewed-by: Cornelia Huck Reviewed-by: Christian Borntraeger CC: Andreas Faerber Tested-by: Christian Borntraeger Signed-off-by: Cornelia Huck --- hw/s390x/ipl.c | 2 +- target-s390x/cpu.c | 76 ++++++++++++++++++++++++++++--------------- target-s390x/cpu.h | 14 +++++--- target-s390x/helper.c | 25 ++++++-------- target-s390x/kvm.c | 11 ++++--- trace-events | 5 +++ 6 files changed, 81 insertions(+), 52 deletions(-) diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index 4fa9cffded..3b77c9a227 100644 --- a/hw/s390x/ipl.c +++ b/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) diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index 03cab74181..dc89eb30a2 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -26,7 +26,9 @@ #include "cpu.h" #include "qemu-common.h" #include "qemu/timer.h" +#include "qemu/error-report.h" #include "hw/hw.h" +#include "trace.h" #ifndef CONFIG_USER_ONLY #include "sysemu/arch_init.h" #endif @@ -81,7 +83,7 @@ static void s390_cpu_load_normal(CPUState *s) S390CPU *cpu = S390_CPU(s); cpu->env.psw.addr = ldl_phys(s->as, 4) & PSW_MASK_ESA_ADDR; cpu->env.psw.mask = PSW_MASK_32 | PSW_MASK_64; - s390_add_running_cpu(cpu); + s390_cpu_set_state(CPU_STATE_OPERATING, cpu); } #endif @@ -93,11 +95,8 @@ static void s390_cpu_reset(CPUState *s) CPUS390XState *env = &cpu->env; env->pfault_token = -1UL; - s390_del_running_cpu(cpu); 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); } @@ -135,9 +134,8 @@ static void s390_cpu_full_reset(CPUState *s) S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); CPUS390XState *env = &cpu->env; - s390_del_running_cpu(cpu); - scc->parent_reset(s); + s390_cpu_set_state(CPU_STATE_STOPPED, cpu); memset(env, 0, offsetof(CPUS390XState, cpu_num)); @@ -147,12 +145,7 @@ static void s390_cpu_full_reset(CPUState *s) 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; - if (kvm_enabled()) { kvm_s390_reset_vcpu(cpu); } @@ -206,10 +199,7 @@ static void s390_cpu_initfn(Object *obj) env->tod_basetime = 0; 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); - /* 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 env->cpu_num = cpu_num++; env->ext_index = -1; @@ -230,6 +220,12 @@ static void s390_cpu_finalize(Object *obj) } #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; @@ -239,34 +235,60 @@ static unsigned s390_count_running_cpus(void) uint8_t state = S390_CPU(cpu)->env.cpu_state; if (state == CPU_STATE_OPERATING || state == CPU_STATE_LOAD) { - nr_running++; + if (!disabled_wait(cpu)) { + nr_running++; + } } } return nr_running; } -void s390_add_running_cpu(S390CPU *cpu) +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) { - cpu->env.cpu_state = CPU_STATE_OPERATING; cs->halted = 0; cs->exception_index = -1; } } -unsigned s390_del_running_cpu(S390CPU *cpu) -{ - CPUState *cs = CPU(cpu); +unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu) + { + trace_cpu_set_state(CPU(cpu)->cpu_index, cpu_state); - if (cs->halted == 0) { - assert(s390_count_running_cpus() >= 1); - cpu->env.cpu_state = CPU_STATE_STOPPED; - cs->halted = 1; - cs->exception_index = EXCP_HLT; + 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); } + cpu->env.cpu_state = cpu_state; return s390_count_running_cpus(); } diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index f1a3ad263b..7b9300e573 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -407,8 +407,9 @@ static inline void kvm_s390_service_interrupt(uint32_t parm) } #endif 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 */ void s390_sclp_extint(uint32_t parm); @@ -417,11 +418,16 @@ void s390_sclp_extint(uint32_t parm); extern const hwaddr virtio_size; #else -static inline void s390_add_running_cpu(S390CPU *cpu) +static inline unsigned int s390_cpu_halt(S390CPU *cpu) +{ + return 0; +} + +static inline void s390_cpu_unhalt(S390CPU *cpu) { } -static inline unsigned s390_del_running_cpu(S390CPU *cpu) +static inline unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu) { return 0; } diff --git a/target-s390x/helper.c b/target-s390x/helper.c index e21afe6b46..09aec7b42e 100644 --- a/target-s390x/helper.c +++ b/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) { - if (mask & PSW_MASK_WAIT) { - 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) { -#ifndef CONFIG_USER_ONLY - qemu_system_shutdown_request(); -#endif - } - } - cs->halted = 1; - cs->exception_index = EXCP_HLT; - } - env->psw.addr = addr; env->psw.mask = mask; env->cc_op = (mask >> 44) & 3; + + if (mask & PSW_MASK_WAIT) { + S390CPU *cpu = s390_env_get_cpu(env); + if (s390_cpu_halt(cpu) == 0) { +#ifndef CONFIG_USER_ONLY + qemu_system_shutdown_request(); +#endif + } + } } 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", __func__, cs->exception_index, env->psw.addr); - s390_add_running_cpu(cpu); + s390_cpu_set_state(CPU_STATE_OPERATING, cpu); /* handle machine checks */ if ((env->psw.mask & PSW_MASK_MCHECK) && (cs->exception_index == -1)) { diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index a85a480c6a..415baea514 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -921,7 +921,7 @@ static void sigp_cpu_start(void *arg) CPUState *cs = arg; 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); } @@ -934,7 +934,7 @@ static void sigp_cpu_restart(void *arg) }; 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) @@ -1074,7 +1074,7 @@ static void unmanageable_intercept(S390CPU *cpu, const char *str, int pswoffset) error_report("Unmanageable %s! CPU%i new PSW: 0x%016lx:%016lx", str, cs->cpu_index, ldq_phys(cs->as, cpu->env.psa + pswoffset), ldq_phys(cs->as, cpu->env.psa + pswoffset + 8)); - s390_del_running_cpu(cpu); + s390_cpu_halt(cpu); guest_panicked(); } @@ -1103,7 +1103,8 @@ static int handle_intercept(S390CPU *cpu) break; case ICPT_WAITPSW: /* 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)) { qemu_system_shutdown_request(); } else { @@ -1113,7 +1114,7 @@ static int handle_intercept(S390CPU *cpu) r = EXCP_HALTED; break; 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(); } r = EXCP_HALTED; diff --git a/trace-events b/trace-events index 011d1059f8..5202f205a0 100644 --- a/trace-events +++ b/trace-events @@ -1372,3 +1372,8 @@ kvm_clear_cmma(int rc) "CMMA: clearing with result code %d" # 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" + +# 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" From c9e659c9ee75d33ff11a8573cea738ad26bb6f86 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 30 Sep 2014 10:57:30 +0200 Subject: [PATCH 4/8] s390x/kvm: propagate s390 cpu state to kvm Let QEMU propagate the cpu state to kvm. If kvm doesn't yet support it, it is silently ignored as kvm will still handle the cpu state itself in that case. The state is not synced back, thus kvm won't have a chance to actively modify the cpu state. To do so, control has to be given back to QEMU (which is already done so in all relevant cases). Setting of the cpu state can fail either because kvm doesn't support the interface yet, or because the state is invalid/not supported. Failed attempts will be traced Signed-off-by: David Hildenbrand Signed-off-by: Jens Freimann Reviewed-by: Thomas Huth Reviewed-by: Cornelia Huck CC: Andreas Faerber Tested-by: Christian Borntraeger Signed-off-by: Cornelia Huck --- target-s390x/cpu.c | 3 +++ target-s390x/cpu.h | 5 +++++ target-s390x/kvm.c | 43 +++++++++++++++++++++++++++++++++++++++++-- trace-events | 1 + 4 files changed, 50 insertions(+), 2 deletions(-) diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index dc89eb30a2..9dbb0dfcdb 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -288,6 +288,9 @@ unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu) 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(); diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 7b9300e573..6b3aaed842 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -1072,6 +1072,7 @@ int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch, int kvm_s390_cpu_restart(S390CPU *cpu); int kvm_s390_get_memslot_count(KVMState *s); void kvm_s390_clear_cmma_callback(void *opaque); +int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state); #else static inline void kvm_s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, @@ -1102,6 +1103,10 @@ static inline int kvm_s390_get_memslot_count(KVMState *s) { return MAX_AVAIL_SLOTS; } +static inline int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state) +{ + return -ENOSYS; +} #endif static inline void cmma_reset(S390CPU *cpu) diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 415baea514..7c90b18631 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -181,9 +181,10 @@ unsigned long kvm_arch_vcpu_id(CPUState *cpu) 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; } @@ -1321,3 +1322,41 @@ int kvm_s390_get_memslot_count(KVMState *s) { 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; +} diff --git a/trace-events b/trace-events index 5202f205a0..529080640a 100644 --- a/trace-events +++ b/trace-events @@ -1369,6 +1369,7 @@ mhp_pc_dimm_assigned_address(uint64_t addr) "0x%"PRIx64 # target-s390x/kvm.c kvm_enable_cmma(int rc) "CMMA: enabling 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 i8257_unregistered_dma(int nchan, int dma_pos, int dma_len) "unregistered DMA channel used nchan=%d dma_pos=%d dma_len=%d" From 99607144a423dd2cd3113587e36bc4dc65c4ddf1 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 30 Sep 2014 10:57:31 +0200 Subject: [PATCH 5/8] s390x/kvm: reuse kvm_s390_reset_vcpu() to get rid of ifdefs This patch reuses kvm_s390_reset_vcpu() to get rid of some CONFIG_KVM and CONFIG_USER_ONLY ifdefs in cpu.c. In order to get rid of CONFIG_USER_ONLY, kvm_s390_reset_vcpu() has to provide a dummy implementation - the two definitions are moved to the proper section in cpu.h. Signed-off-by: David Hildenbrand Signed-off-by: Jens Freimann Reviewed-by: Cornelia Huck CC: Andreas Faerber Tested-by: Christian Borntraeger Signed-off-by: Cornelia Huck --- target-s390x/cpu.c | 9 ++------- target-s390x/cpu.h | 8 ++++---- target-s390x/kvm.c | 2 +- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index 9dbb0dfcdb..ec7df90dcd 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -117,14 +117,10 @@ static void s390_cpu_initial_reset(CPUState *s) 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"); - } + kvm_s390_reset_vcpu(cpu); } -#endif } /* CPUClass:reset() */ @@ -145,11 +141,10 @@ static void s390_cpu_full_reset(CPUState *s) env->pfault_token = -1UL; -#if !defined(CONFIG_USER_ONLY) + /* Reset state inside the kernel that we cannot access yet from QEMU. */ if (kvm_enabled()) { kvm_s390_reset_vcpu(cpu); } -#endif tlb_flush(s, 1); } diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 6b3aaed842..fe2f95d084 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -389,16 +389,12 @@ int s390_virtio_hypercall(CPUS390XState *env); void s390_virtio_irq(int config_change, uint64_t token); #ifdef CONFIG_KVM -void kvm_s390_reset_vcpu(S390CPU *cpu); void kvm_s390_virtio_irq(int config_change, uint64_t token); void kvm_s390_service_interrupt(uint32_t parm); void kvm_s390_vcpu_interrupt(S390CPU *cpu, 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); #else -static inline void kvm_s390_reset_vcpu(S390CPU *cpu) -{ -} static inline void kvm_s390_virtio_irq(int config_change, uint64_t token) { } @@ -1073,6 +1069,7 @@ int kvm_s390_cpu_restart(S390CPU *cpu); int kvm_s390_get_memslot_count(KVMState *s); 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 static inline void kvm_s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, @@ -1107,6 +1104,9 @@ 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 static inline void cmma_reset(S390CPU *cpu) diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 7c90b18631..e4c4c8dc18 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -198,7 +198,7 @@ void kvm_s390_reset_vcpu(S390CPU *cpu) * Before this ioctl cpu_synchronize_state() is called in common kvm * code (kvm-all) */ 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); } } From 71dd7e69b30dc5024a8d891e7011173a81fe7a72 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 30 Sep 2014 10:57:32 +0200 Subject: [PATCH 6/8] s390x/kvm: synchronize the cpu state after SIGP (INITIAL) CPU RESET We need to synchronize registers after a reset has been performed. The current code does that in qemu_system_reset(), load_normal_reset() and modified_clear_reset() for all vcpus. After SIGP (INITIAL) CPU RESET, this needs to be done for the targeted vcpu as well, so let's call cpu_synchronize_post_reset() in the respective handlers. Signed-off-by: David Hildenbrand Signed-off-by: Jens Freimann Reviewed-by: Cornelia Huck CC: Andreas Faerber Tested-by: Christian Borntraeger Signed-off-by: Cornelia Huck --- target-s390x/kvm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index e4c4c8dc18..5b10a255ed 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -952,6 +952,7 @@ static void sigp_initial_cpu_reset(void *arg) cpu_synchronize_state(cpu); scc->initial_cpu_reset(cpu); + cpu_synchronize_post_reset(cpu); } static void sigp_cpu_reset(void *arg) @@ -961,6 +962,7 @@ static void sigp_cpu_reset(void *arg) cpu_synchronize_state(cpu); scc->cpu_reset(cpu); + cpu_synchronize_post_reset(cpu); } #define SIGP_ORDER_MASK 0x000000ff From ef1df13087768c0ab4010355595b0e3dd91bbd3c Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 30 Sep 2014 10:58:42 +0200 Subject: [PATCH 7/8] s390x/migration: migrate CPU state This patch provides the cpu save information for dumps and later life migration and enables migration of the CPU state. The code is based on earlier work from Christian Borntraeger and Jason Herne. Signed-off-by: Thomas Huth Signed-off-by: David Hildenbrand [provide cpu_post_load()] Signed-off-by: Jens Freimann CC: Andreas Faerber CC: Christian Borntraeger CC: Jason J. Herne Tested-by: Christian Borntraeger [Cornelia Huck: tweaked cpu_post_load() comment] Signed-off-by: Cornelia Huck --- target-s390x/Makefile.objs | 2 +- target-s390x/cpu-qom.h | 4 ++ target-s390x/cpu.c | 7 +--- target-s390x/machine.c | 76 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 7 deletions(-) create mode 100644 target-s390x/machine.c diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs index f8731463ff..2c5749447f 100644 --- a/target-s390x/Makefile.objs +++ b/target-s390x/Makefile.objs @@ -1,5 +1,5 @@ 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 += 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 diff --git a/target-s390x/cpu-qom.h b/target-s390x/cpu-qom.h index 4f7d4cbe14..8b376df1b7 100644 --- a/target-s390x/cpu-qom.h +++ b/target-s390x/cpu-qom.h @@ -77,6 +77,10 @@ static inline S390CPU *s390_env_get_cpu(CPUS390XState *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); bool s390_cpu_exec_interrupt(CPUState *cpu, int int_req); void s390_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index ec7df90dcd..d2f6312e03 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -292,11 +292,6 @@ unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu) } #endif -static const VMStateDescription vmstate_s390_cpu = { - .name = "cpu", - .unmigratable = 1, -}; - static void s390_cpu_class_init(ObjectClass *oc, void *data) { S390CPUClass *scc = S390_CPU_CLASS(oc); @@ -323,11 +318,11 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data) cc->handle_mmu_fault = s390_cpu_handle_mmu_fault; #else 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_qemunote = s390_cpu_write_elf64_qemunote; cc->cpu_exec_interrupt = s390_cpu_exec_interrupt; #endif - dc->vmsd = &vmstate_s390_cpu; cc->gdb_num_core_regs = S390_NUM_CORE_REGS; cc->gdb_core_xml_file = "s390x-core64.xml"; } diff --git a/target-s390x/machine.c b/target-s390x/machine.c new file mode 100644 index 0000000000..fbcb0d0863 --- /dev/null +++ b/target-s390x/machine.c @@ -0,0 +1,76 @@ +/* + * S390x machine definitions and functions + * + * Copyright IBM Corp. 2014 + * + * Authors: + * Thomas Huth + * Christian Borntraeger + * Jason J. Herne + * + * 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() + }, +}; From 4b7757bae7c94f980969031119db12d540cf2b61 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Tue, 30 Sep 2014 13:55:04 +0200 Subject: [PATCH 8/8] s390x/virtio-ccw: fix vhost-scsi intialization The vhost-scsi-ccw backend is of type VHostSCSICcw, not VirtIOSCSICcw. This fixes a segfault when invoking qemu-system-s390x -device vhost-scsi-ccw,? Reviewed-by: Thomas Huth Tested-by: Christian Borntraeger Signed-off-by: Cornelia Huck --- hw/s390x/virtio-ccw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index e7d3ea178a..18ba29fa14 100644 --- a/hw/s390x/virtio-ccw.c +++ b/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 = { .name = TYPE_VHOST_SCSI_CCW, .parent = TYPE_VIRTIO_CCW_DEVICE, - .instance_size = sizeof(VirtIOSCSICcw), + .instance_size = sizeof(VHostSCSICcw), .instance_init = vhost_ccw_scsi_instance_init, .class_init = vhost_ccw_scsi_class_init, };