void s390_crw_mchk(void) { S390FLICState *fs = s390_get_flic(); S390FLICStateClass *fsc = s390_get_flic_class(fs); fsc->inject_crw_mchk(fs); }
/* * All of the following interrupts are floating, i.e. not per-vcpu. * We just need a dummy cpustate in order to be able to inject in the * non-kvm case. */ void s390_sclp_extint(uint32_t parm) { S390FLICState *fs = s390_get_flic(); S390FLICStateClass *fsc = s390_get_flic_class(fs); fsc->inject_service(fs, parm); }
void s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, uint32_t io_int_parm, uint32_t io_int_word) { S390FLICState *fs = s390_get_flic(); S390FLICStateClass *fsc = s390_get_flic_class(fs); fsc->inject_io(fs, subchannel_id, subchannel_nr, io_int_parm, io_int_word); }
bool s390_cpu_has_io_int(S390CPU *cpu) { QEMUS390FLICState *flic = s390_get_qemu_flic(s390_get_flic()); CPUS390XState *env = &cpu->env; if (!(env->psw.mask & PSW_MASK_IO)) { return false; } return qemu_s390_flic_has_io(flic, env->cregs[6]); }
bool s390_cpu_has_mcck_int(S390CPU *cpu) { QEMUS390FLICState *flic = s390_get_qemu_flic(s390_get_flic()); CPUS390XState *env = &cpu->env; if (!(env->psw.mask & PSW_MASK_MCHECK)) { return false; } /* for now we only support channel report machine checks (floating) */ if (qemu_s390_flic_has_crw_mchk(flic) && (env->cregs[14] & CR14_CHANNEL_REPORT_SC)) { return true; } return false; }
bool s390_cpu_has_ext_int(S390CPU *cpu) { QEMUS390FLICState *flic = s390_get_qemu_flic(s390_get_flic()); CPUS390XState *env = &cpu->env; if (!(env->psw.mask & PSW_MASK_EXT)) { return false; } if ((env->pending_int & INTERRUPT_EMERGENCY_SIGNAL) && (env->cregs[0] & CR0_EMERGENCY_SIGNAL_SC)) { return true; } if ((env->pending_int & INTERRUPT_EXTERNAL_CALL) && (env->cregs[0] & CR0_EXTERNAL_CALL_SC)) { return true; } if ((env->pending_int & INTERRUPT_EXTERNAL_CALL) && (env->cregs[0] & CR0_EXTERNAL_CALL_SC)) { return true; } if ((env->pending_int & INTERRUPT_EXT_CLOCK_COMPARATOR) && (env->cregs[0] & CR0_CKC_SC)) { return true; } if ((env->pending_int & INTERRUPT_EXT_CPU_TIMER) && (env->cregs[0] & CR0_CPU_TIMER_SC)) { return true; } if (qemu_s390_flic_has_service(flic) && (env->cregs[0] & CR0_SERVICE_SC)) { return true; } return false; }
/** * 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; } 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 * @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; } int kvm_s390_inject_flic(struct kvm_s390_irq *irq) { static KVMS390FLICState *flic; if (unlikely(!flic)) { flic = KVM_S390_FLIC(s390_get_flic()); } return flic_enqueue_irqs(irq, sizeof(*irq), flic); } static int kvm_s390_clear_io_flic(S390FLICState *fs, uint16_t subchannel_id, uint16_t subchannel_nr) { KVMS390FLICState *flic = KVM_S390_FLIC(fs); int rc; uint32_t sid = subchannel_id << 16 | subchannel_nr; struct kvm_device_attr attr = { .group = KVM_DEV_FLIC_CLEAR_IO_IRQ, .addr = (uint64_t) &sid, .attr = sizeof(sid), }; if (unlikely(!flic->clear_io_supported)) { return -ENOSYS; } 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; }