static void do_svc_interrupt(CPUS390XState *env) { uint64_t mask, addr; LowCore *lowcore; lowcore = cpu_map_lowcore(env); lowcore->svc_code = cpu_to_be16(env->int_svc_code); lowcore->svc_ilen = cpu_to_be16(env->int_svc_ilen); lowcore->svc_old_psw.mask = cpu_to_be64(get_psw_mask(env)); lowcore->svc_old_psw.addr = cpu_to_be64(env->psw.addr + env->int_svc_ilen); mask = be64_to_cpu(lowcore->svc_new_psw.mask); addr = be64_to_cpu(lowcore->svc_new_psw.addr); cpu_unmap_lowcore(lowcore); load_psw(env, mask, addr); /* When a PER event is pending, the PER exception has to happen immediately after the SERVICE CALL one. */ if (env->per_perc_atmid) { env->int_pgm_code = PGM_PER; env->int_pgm_ilen = env->int_svc_ilen; do_program_interrupt(env); } }
void do_restart_interrupt(CPUS390XState *env) { uint64_t mask, addr; LowCore *lowcore; lowcore = cpu_map_lowcore(env); lowcore->restart_old_psw.mask = cpu_to_be64(get_psw_mask(env)); lowcore->restart_old_psw.addr = cpu_to_be64(env->psw.addr); mask = be64_to_cpu(lowcore->restart_new_psw.mask); addr = be64_to_cpu(lowcore->restart_new_psw.addr); cpu_unmap_lowcore(lowcore); load_psw(env, mask, addr); }
static void do_program_interrupt(CPUS390XState *env) { uint64_t mask, addr; LowCore *lowcore; int ilen = env->int_pgm_ilen; switch (ilen) { case ILEN_LATER: ilen = get_ilen(cpu_ldub_code(env, env->psw.addr)); break; case ILEN_LATER_INC: ilen = get_ilen(cpu_ldub_code(env, env->psw.addr)); env->psw.addr += ilen; break; default: assert(ilen == 2 || ilen == 4 || ilen == 6); } qemu_log_mask(CPU_LOG_INT, "%s: code=0x%x ilen=%d\n", __func__, env->int_pgm_code, ilen); lowcore = cpu_map_lowcore(env); /* Signal PER events with the exception. */ if (env->per_perc_atmid) { env->int_pgm_code |= PGM_PER; lowcore->per_address = cpu_to_be64(env->per_address); lowcore->per_perc_atmid = cpu_to_be16(env->per_perc_atmid); env->per_perc_atmid = 0; } lowcore->pgm_ilen = cpu_to_be16(ilen); lowcore->pgm_code = cpu_to_be16(env->int_pgm_code); lowcore->program_old_psw.mask = cpu_to_be64(get_psw_mask(env)); lowcore->program_old_psw.addr = cpu_to_be64(env->psw.addr); mask = be64_to_cpu(lowcore->program_new_psw.mask); addr = be64_to_cpu(lowcore->program_new_psw.addr); lowcore->per_breaking_event_addr = cpu_to_be64(env->gbea); cpu_unmap_lowcore(lowcore); DPRINTF("%s: %x %x %" PRIx64 " %" PRIx64 "\n", __func__, env->int_pgm_code, ilen, env->psw.mask, env->psw.addr); load_psw(env, mask, addr); }
static void do_svc_interrupt(CPUS390XState *env) { uint64_t mask, addr; LowCore *lowcore; lowcore = cpu_map_lowcore(env); lowcore->svc_code = cpu_to_be16(env->int_svc_code); lowcore->svc_ilen = cpu_to_be16(env->int_svc_ilen); lowcore->svc_old_psw.mask = cpu_to_be64(get_psw_mask(env)); lowcore->svc_old_psw.addr = cpu_to_be64(env->psw.addr + env->int_svc_ilen); mask = be64_to_cpu(lowcore->svc_new_psw.mask); addr = be64_to_cpu(lowcore->svc_new_psw.addr); cpu_unmap_lowcore(lowcore); load_psw(env, mask, addr); }
static void do_ext_interrupt(CPUS390XState *env) { S390CPU *cpu = s390_env_get_cpu(env); uint64_t mask, addr; LowCore *lowcore; ExtQueue *q; if (!(env->psw.mask & PSW_MASK_EXT)) { cpu_abort(CPU(cpu), "Ext int w/o ext mask\n"); } if (env->ext_index < 0 || env->ext_index >= MAX_EXT_QUEUE) { cpu_abort(CPU(cpu), "Ext queue overrun: %d\n", env->ext_index); } q = &env->ext_queue[env->ext_index]; lowcore = cpu_map_lowcore(env); lowcore->ext_int_code = cpu_to_be16(q->code); lowcore->ext_params = cpu_to_be32(q->param); lowcore->ext_params2 = cpu_to_be64(q->param64); lowcore->external_old_psw.mask = cpu_to_be64(get_psw_mask(env)); lowcore->external_old_psw.addr = cpu_to_be64(env->psw.addr); lowcore->cpu_addr = cpu_to_be16(env->cpu_num | VIRTIO_SUBCODE_64); mask = be64_to_cpu(lowcore->external_new_psw.mask); addr = be64_to_cpu(lowcore->external_new_psw.addr); cpu_unmap_lowcore(lowcore); env->ext_index--; if (env->ext_index == -1) { env->pending_int &= ~INTERRUPT_EXT; } DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __func__, env->psw.mask, env->psw.addr); load_psw(env, mask, addr); }
static void do_program_interrupt(CPUS390XState *env) { uint64_t mask, addr; LowCore *lowcore; int ilen = env->int_pgm_ilen; switch (ilen) { case ILEN_LATER: ilen = get_ilen(cpu_ldub_code(env, env->psw.addr)); break; case ILEN_LATER_INC: ilen = get_ilen(cpu_ldub_code(env, env->psw.addr)); env->psw.addr += ilen; break; default: assert(ilen == 2 || ilen == 4 || ilen == 6); } qemu_log_mask(CPU_LOG_INT, "%s: code=0x%x ilen=%d\n", __func__, env->int_pgm_code, ilen); lowcore = cpu_map_lowcore(env); lowcore->pgm_ilen = cpu_to_be16(ilen); lowcore->pgm_code = cpu_to_be16(env->int_pgm_code); lowcore->program_old_psw.mask = cpu_to_be64(get_psw_mask(env)); lowcore->program_old_psw.addr = cpu_to_be64(env->psw.addr); mask = be64_to_cpu(lowcore->program_new_psw.mask); addr = be64_to_cpu(lowcore->program_new_psw.addr); cpu_unmap_lowcore(lowcore); DPRINTF("%s: %x %x %" PRIx64 " %" PRIx64 "\n", __func__, env->int_pgm_code, ilen, env->psw.mask, env->psw.addr); load_psw(env, mask, addr); }
void HELPER(load_psw)(CPUS390XState *env, uint64_t mask, uint64_t addr) { load_psw(env, mask, addr); cpu_loop_exit(CPU(s390_env_get_cpu(env))); }
static void do_mchk_interrupt(CPUS390XState *env) { S390CPU *cpu = s390_env_get_cpu(env); uint64_t mask, addr; LowCore *lowcore; MchkQueue *q; int i; if (!(env->psw.mask & PSW_MASK_MCHECK)) { cpu_abort(CPU(cpu), "Machine check w/o mchk mask\n"); } if (env->mchk_index < 0 || env->mchk_index >= MAX_MCHK_QUEUE) { cpu_abort(CPU(cpu), "Mchk queue overrun: %d\n", env->mchk_index); } q = &env->mchk_queue[env->mchk_index]; if (q->type != 1) { /* Don't know how to handle this... */ cpu_abort(CPU(cpu), "Unknown machine check type %d\n", q->type); } if (!(env->cregs[14] & (1 << 28))) { /* CRW machine checks disabled */ return; } lowcore = cpu_map_lowcore(env); for (i = 0; i < 16; i++) { lowcore->floating_pt_save_area[i] = cpu_to_be64(get_freg(env, i)->ll); lowcore->gpregs_save_area[i] = cpu_to_be64(env->regs[i]); lowcore->access_regs_save_area[i] = cpu_to_be32(env->aregs[i]); lowcore->cregs_save_area[i] = cpu_to_be64(env->cregs[i]); } lowcore->prefixreg_save_area = cpu_to_be32(env->psa); lowcore->fpt_creg_save_area = cpu_to_be32(env->fpc); lowcore->tod_progreg_save_area = cpu_to_be32(env->todpr); lowcore->cpu_timer_save_area[0] = cpu_to_be32(env->cputm >> 32); lowcore->cpu_timer_save_area[1] = cpu_to_be32((uint32_t)env->cputm); lowcore->clock_comp_save_area[0] = cpu_to_be32(env->ckc >> 32); lowcore->clock_comp_save_area[1] = cpu_to_be32((uint32_t)env->ckc); lowcore->mcck_interruption_code[0] = cpu_to_be32(0x00400f1d); lowcore->mcck_interruption_code[1] = cpu_to_be32(0x40330000); lowcore->mcck_old_psw.mask = cpu_to_be64(get_psw_mask(env)); lowcore->mcck_old_psw.addr = cpu_to_be64(env->psw.addr); mask = be64_to_cpu(lowcore->mcck_new_psw.mask); addr = be64_to_cpu(lowcore->mcck_new_psw.addr); cpu_unmap_lowcore(lowcore); env->mchk_index--; if (env->mchk_index == -1) { env->pending_int &= ~INTERRUPT_MCHK; } DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __func__, env->psw.mask, env->psw.addr); load_psw(env, mask, addr); }
static void do_io_interrupt(CPUS390XState *env) { S390CPU *cpu = s390_env_get_cpu(env); LowCore *lowcore; IOIntQueue *q; uint8_t isc; int disable = 1; int found = 0; if (!(env->psw.mask & PSW_MASK_IO)) { cpu_abort(CPU(cpu), "I/O int w/o I/O mask\n"); } for (isc = 0; isc < ARRAY_SIZE(env->io_index); isc++) { uint64_t isc_bits; if (env->io_index[isc] < 0) { continue; } if (env->io_index[isc] >= MAX_IO_QUEUE) { cpu_abort(CPU(cpu), "I/O queue overrun for isc %d: %d\n", isc, env->io_index[isc]); } q = &env->io_queue[env->io_index[isc]][isc]; isc_bits = ISC_TO_ISC_BITS(IO_INT_WORD_ISC(q->word)); if (!(env->cregs[6] & isc_bits)) { disable = 0; continue; } if (!found) { uint64_t mask, addr; found = 1; lowcore = cpu_map_lowcore(env); lowcore->subchannel_id = cpu_to_be16(q->id); lowcore->subchannel_nr = cpu_to_be16(q->nr); lowcore->io_int_parm = cpu_to_be32(q->parm); lowcore->io_int_word = cpu_to_be32(q->word); lowcore->io_old_psw.mask = cpu_to_be64(get_psw_mask(env)); lowcore->io_old_psw.addr = cpu_to_be64(env->psw.addr); mask = be64_to_cpu(lowcore->io_new_psw.mask); addr = be64_to_cpu(lowcore->io_new_psw.addr); cpu_unmap_lowcore(lowcore); env->io_index[isc]--; DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __func__, env->psw.mask, env->psw.addr); load_psw(env, mask, addr); } if (env->io_index[isc] >= 0) { disable = 0; } continue; } if (disable) { env->pending_int &= ~INTERRUPT_IO; } }