From 3cda44f7bae5c9feddc11630ba6eecb2e3bed425 Mon Sep 17 00:00:00 2001 From: Jens Freimann Date: Mon, 2 Mar 2015 17:44:24 +0100 Subject: [PATCH] s390x/kvm: migrate vcpu interrupt state This patch adds support to migrate vcpu interrupts. We use ioctl KVM_S390_GET_IRQ_STATE and _SET_IRQ_STATE to get/set the complete interrupt state for a vcpu. Reviewed-by: David Hildenbrand Signed-off-by: Jens Freimann Signed-off-by: Cornelia Huck --- target-s390x/cpu-qom.h | 3 +++ target-s390x/cpu.c | 1 + target-s390x/cpu.h | 9 +++++++ target-s390x/kvm.c | 55 ++++++++++++++++++++++++++++++++++++++++++ target-s390x/machine.c | 15 +++++++++++- 5 files changed, 82 insertions(+), 1 deletion(-) diff --git a/target-s390x/cpu-qom.h b/target-s390x/cpu-qom.h index 8b376df1b7..936ae21e06 100644 --- a/target-s390x/cpu-qom.h +++ b/target-s390x/cpu-qom.h @@ -66,6 +66,9 @@ typedef struct S390CPU { /*< public >*/ CPUS390XState env; + /* needed for live migration */ + void *irqstate; + uint32_t irqstate_saved_size; } S390CPU; static inline S390CPU *s390_env_get_cpu(CPUS390XState *env) diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index e0537fa222..d2f9836e86 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -213,6 +213,7 @@ static void s390_cpu_finalize(Object *obj) S390CPU *cpu = S390_CPU(obj); qemu_unregister_reset(s390_cpu_machine_reset_cb, cpu); + g_free(cpu->irqstate); #endif } diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index ba7d250962..c55721114e 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -1079,6 +1079,8 @@ 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); int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit, uint64_t *hw_limit); +void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu); +int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu); #else static inline void kvm_s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, @@ -1121,6 +1123,13 @@ static inline int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit, { return 0; } +static inline void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu) +{ +} +static inline int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu) +{ + return 0; +} #endif static inline int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit) diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 43ad0094b6..aba1265eb9 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -109,6 +109,14 @@ #define ICPT_CPU_STOP 0x28 #define ICPT_IO 0x40 +#define NR_LOCAL_IRQS 32 +/* + * Needs to be big enough to contain max_cpus emergency signals + * and in addition NR_LOCAL_IRQS interrupts + */ +#define VCPU_IRQ_BUF_SIZE (sizeof(struct kvm_s390_irq) * \ + (max_cpus + NR_LOCAL_IRQS)) + static CPUWatchpoint hw_watchpoint; /* * We don't use a list because this structure is also used to transmit the @@ -274,6 +282,7 @@ int kvm_arch_init_vcpu(CPUState *cs) { S390CPU *cpu = S390_CPU(cs); kvm_s390_set_cpu_state(cpu, cpu->env.cpu_state); + cpu->irqstate = g_malloc0(VCPU_IRQ_BUF_SIZE); return 0; } @@ -2059,6 +2068,52 @@ int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state) return ret; } +void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu) +{ + struct kvm_s390_irq_state irq_state; + CPUState *cs = CPU(cpu); + int32_t bytes; + + if (!kvm_check_extension(kvm_state, KVM_CAP_S390_IRQ_STATE)) { + return; + } + + irq_state.buf = (uint64_t) cpu->irqstate; + irq_state.len = VCPU_IRQ_BUF_SIZE; + + bytes = kvm_vcpu_ioctl(cs, KVM_S390_GET_IRQ_STATE, &irq_state); + if (bytes < 0) { + cpu->irqstate_saved_size = 0; + error_report("Migration of interrupt state failed"); + return; + } + + cpu->irqstate_saved_size = bytes; +} + +int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu) +{ + CPUState *cs = CPU(cpu); + struct kvm_s390_irq_state irq_state; + int r; + + if (!kvm_check_extension(kvm_state, KVM_CAP_S390_IRQ_STATE)) { + return -ENOSYS; + } + + if (cpu->irqstate_saved_size == 0) { + return 0; + } + irq_state.buf = (uint64_t) cpu->irqstate; + irq_state.len = cpu->irqstate_saved_size; + + r = kvm_vcpu_ioctl(cs, KVM_S390_SET_IRQ_STATE, &irq_state); + if (r) { + error_report("Setting interrupt state failed %d", r); + } + return r; +} + int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, uint64_t address, uint32_t data) { diff --git a/target-s390x/machine.c b/target-s390x/machine.c index a034423447..7853e3c989 100644 --- a/target-s390x/machine.c +++ b/target-s390x/machine.c @@ -28,10 +28,19 @@ static int cpu_post_load(void *opaque, int version_id) */ if (kvm_enabled()) { kvm_s390_set_cpu_state(cpu, cpu->env.cpu_state); + return kvm_s390_vcpu_interrupt_post_load(cpu); } return 0; } +static void cpu_pre_save(void *opaque) +{ + S390CPU *cpu = opaque; + + if (kvm_enabled()) { + kvm_s390_vcpu_interrupt_pre_save(cpu); + } +} const VMStateDescription vmstate_fpu = { .name = "cpu/fpu", @@ -67,7 +76,8 @@ static inline bool fpu_needed(void *opaque) const VMStateDescription vmstate_s390_cpu = { .name = "cpu", .post_load = cpu_post_load, - .version_id = 3, + .pre_save = cpu_pre_save, + .version_id = 4, .minimum_version_id = 3, .fields = (VMStateField[]) { VMSTATE_UINT64_ARRAY(env.regs, S390CPU, 16), @@ -86,6 +96,9 @@ const VMStateDescription vmstate_s390_cpu = { VMSTATE_UINT64_ARRAY(env.cregs, S390CPU, 16), VMSTATE_UINT8(env.cpu_state, S390CPU), VMSTATE_UINT8(env.sigp_order, S390CPU), + VMSTATE_UINT32_V(irqstate_saved_size, S390CPU, 4), + VMSTATE_VBUFFER_UINT32(irqstate, S390CPU, 4, NULL, 0, + irqstate_saved_size), VMSTATE_END_OF_LIST() }, .subsections = (VMStateSubsection[]) {