diff options
Diffstat (limited to 'target-s390x/kvm.c')
-rw-r--r-- | target-s390x/kvm.c | 77 |
1 files changed, 75 insertions, 2 deletions
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 08cbffbe36..ea18015793 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -110,6 +110,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 @@ -125,6 +133,7 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = { static int cap_sync_regs; static int cap_async_pf; static int cap_mem_op; +static int cap_s390_irq; static void *legacy_s390_alloc(size_t size, uint64_t *align); @@ -250,6 +259,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) cap_sync_regs = kvm_check_extension(s, KVM_CAP_SYNC_REGS); cap_async_pf = kvm_check_extension(s, KVM_CAP_ASYNC_PF); cap_mem_op = kvm_check_extension(s, KVM_CAP_S390_MEM_OP); + cap_s390_irq = kvm_check_extension(s, KVM_CAP_S390_INJECT_IRQ); kvm_s390_enable_cmma(s); @@ -273,6 +283,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; } @@ -829,10 +840,9 @@ static int s390_kvm_irq_to_interrupt(struct kvm_s390_irq *irq, return r; } -void kvm_s390_vcpu_interrupt(S390CPU *cpu, struct kvm_s390_irq *irq) +static void inject_vcpu_irq_legacy(CPUState *cs, struct kvm_s390_irq *irq) { struct kvm_s390_interrupt kvmint = {}; - CPUState *cs = CPU(cpu); int r; r = s390_kvm_irq_to_interrupt(irq, &kvmint); @@ -848,6 +858,23 @@ void kvm_s390_vcpu_interrupt(S390CPU *cpu, struct kvm_s390_irq *irq) } } +void kvm_s390_vcpu_interrupt(S390CPU *cpu, struct kvm_s390_irq *irq) +{ + CPUState *cs = CPU(cpu); + int r; + + if (cap_s390_irq) { + r = kvm_vcpu_ioctl(cs, KVM_S390_IRQ, irq); + if (!r) { + return; + } + error_report("KVM failed to inject interrupt %llx", irq->type); + exit(1); + } + + inject_vcpu_irq_legacy(cs, irq); +} + static void __kvm_s390_floating_interrupt(struct kvm_s390_irq *irq) { struct kvm_s390_interrupt kvmint = {}; @@ -2043,6 +2070,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) { |