Example #1
0
void s390_crw_mchk(void)
{
    S390FLICState *fs = s390_get_flic();
    S390FLICStateClass *fsc = s390_get_flic_class(fs);

    fsc->inject_crw_mchk(fs);
}
Example #2
0
/*
 * 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);
}
Example #3
0
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);
}
Example #4
0
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]);
}
Example #5
0
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;
}
Example #6
0
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;
}
Example #7
0
/**
 * 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;
}