diff --git a/linux-user/main.c b/linux-user/main.c index f6c4c8d7a30b9b6dcbda37ee5024bc9182020fea..15bacb9a3034890062051f3ffaa99461217b6766 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2933,71 +2933,115 @@ void cpu_loop(CPUAlphaState *env) #ifdef TARGET_S390X void cpu_loop(CPUS390XState *env) { - int trapnr; + int trapnr, n, sig; target_siginfo_t info; + target_ulong addr; while (1) { - trapnr = cpu_s390x_exec (env); - + trapnr = cpu_s390x_exec(env); switch (trapnr) { case EXCP_INTERRUPT: - /* just indicate that signals should be handled asap */ + /* Just indicate that signals should be handled asap. */ break; - case EXCP_DEBUG: - { - int sig; - sig = gdb_handlesig (env, TARGET_SIGTRAP); - if (sig) { - info.si_signo = sig; - info.si_errno = 0; - info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); - } + case EXCP_SVC: + n = env->int_svc_code; + if (!n) { + /* syscalls > 255 */ + n = env->regs[1]; } + env->psw.addr += env->int_svc_ilen; + env->regs[2] = do_syscall(env, n, env->regs[2], env->regs[3], + env->regs[4], env->regs[5], + env->regs[6], env->regs[7], 0, 0); break; - case EXCP_SVC: - { - int n = env->int_svc_code; - if (!n) { - /* syscalls > 255 */ - n = env->regs[1]; - } - env->psw.addr += env->int_svc_ilc; - env->regs[2] = do_syscall(env, n, - env->regs[2], - env->regs[3], - env->regs[4], - env->regs[5], - env->regs[6], - env->regs[7], - 0, 0); + + case EXCP_DEBUG: + sig = gdb_handlesig(env, TARGET_SIGTRAP); + if (sig) { + n = TARGET_TRAP_BRKPT; + goto do_signal_pc; } break; - case EXCP_ADDR: - { - info.si_signo = SIGSEGV; - info.si_errno = 0; + case EXCP_PGM: + n = env->int_pgm_code; + switch (n) { + case PGM_OPERATION: + case PGM_PRIVILEGED: + sig = SIGILL; + n = TARGET_ILL_ILLOPC; + goto do_signal_pc; + case PGM_PROTECTION: + case PGM_ADDRESSING: + sig = SIGSEGV; /* XXX: check env->error_code */ - info.si_code = TARGET_SEGV_MAPERR; - info._sifields._sigfault._addr = env->__excp_addr; - queue_signal(env, info.si_signo, &info); + n = TARGET_SEGV_MAPERR; + addr = env->__excp_addr; + goto do_signal; + case PGM_EXECUTE: + case PGM_SPECIFICATION: + case PGM_SPECIAL_OP: + case PGM_OPERAND: + do_sigill_opn: + sig = SIGILL; + n = TARGET_ILL_ILLOPN; + goto do_signal_pc; + + case PGM_FIXPT_OVERFLOW: + sig = SIGFPE; + n = TARGET_FPE_INTOVF; + goto do_signal_pc; + case PGM_FIXPT_DIVIDE: + sig = SIGFPE; + n = TARGET_FPE_INTDIV; + goto do_signal_pc; + + case PGM_DATA: + n = (env->fpc >> 8) & 0xff; + if (n == 0xff) { + /* compare-and-trap */ + goto do_sigill_opn; + } else { + /* An IEEE exception, simulated or otherwise. */ + if (n & 0x80) { + n = TARGET_FPE_FLTINV; + } else if (n & 0x40) { + n = TARGET_FPE_FLTDIV; + } else if (n & 0x20) { + n = TARGET_FPE_FLTOVF; + } else if (n & 0x10) { + n = TARGET_FPE_FLTUND; + } else if (n & 0x08) { + n = TARGET_FPE_FLTRES; + } else { + /* ??? Quantum exception; BFP, DFP error. */ + goto do_sigill_opn; + } + sig = SIGFPE; + goto do_signal_pc; + } + + default: + fprintf(stderr, "Unhandled program exception: %#x\n", n); + cpu_dump_state(env, stderr, fprintf, 0); + exit(1); } break; - case EXCP_SPEC: - { - fprintf(stderr,"specification exception insn 0x%08x%04x\n", ldl(env->psw.addr), lduw(env->psw.addr + 4)); - info.si_signo = SIGILL; - info.si_errno = 0; - info.si_code = TARGET_ILL_ILLOPC; - info._sifields._sigfault._addr = env->__excp_addr; - queue_signal(env, info.si_signo, &info); - } + + do_signal_pc: + addr = env->psw.addr; + do_signal: + info.si_signo = sig; + info.si_errno = 0; + info.si_code = n; + info._sifields._sigfault._addr = addr; + queue_signal(env, info.si_signo, &info); break; + default: - printf ("Unhandled trap: 0x%x\n", trapnr); + fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(env, stderr, fprintf, 0); - exit (1); + exit(1); } process_pending_signals (env); } diff --git a/linux-user/s390x/syscall.h b/linux-user/s390x/syscall.h index c2ea151ea52754c714524cac625806b08eda8903..e4603b79c3d47f986633d7cc2703ccd141e20d1b 100644 --- a/linux-user/s390x/syscall.h +++ b/linux-user/s390x/syscall.h @@ -16,7 +16,7 @@ struct target_pt_regs { target_psw_t psw; abi_ulong gprs[TARGET_NUM_GPRS]; abi_ulong orig_gpr2; - unsigned short ilc; + unsigned short ilen; unsigned short trap; }; diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 529716de470e89ed729da8c1774a22f4ca106481..83e618ab0e7657f235253a830df4d630efc195de 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -79,10 +79,10 @@ typedef struct CPUS390XState { uint64_t psa; uint32_t int_pgm_code; - uint32_t int_pgm_ilc; + uint32_t int_pgm_ilen; uint32_t int_svc_code; - uint32_t int_svc_ilc; + uint32_t int_svc_ilen; uint64_t cregs[16]; /* control registers */ @@ -253,25 +253,31 @@ static inline void cpu_get_tb_cpu_state(CPUS390XState* env, target_ulong *pc, ((env->psw.mask & PSW_MASK_32) ? FLAG_MASK_32 : 0); } -static inline int get_ilc(uint8_t opc) +/* While the PoO talks about ILC (a number between 1-3) what is actually + stored in LowCore is shifted left one bit (an even between 2-6). As + this is the actual length of the insn and therefore more useful, that + is what we want to pass around and manipulate. To make sure that we + have applied this distinction universally, rename the "ILC" to "ILEN". */ +static inline int get_ilen(uint8_t opc) { switch (opc >> 6) { case 0: - return 1; + return 2; case 1: case 2: - return 2; - case 3: - return 3; + return 4; + default: + return 6; } - - return 0; } -#define ILC_LATER 0x20 -#define ILC_LATER_INC 0x21 -#define ILC_LATER_INC_2 0x22 - +#ifndef CONFIG_USER_ONLY +/* In several cases of runtime exceptions, we havn't recorded the true + instruction length. Use these codes when raising exceptions in order + to re-compute the length by examining the insn in memory. */ +#define ILEN_LATER 0x20 +#define ILEN_LATER_INC 0x21 +#endif S390CPU *cpu_s390x_init(const char *cpu_model); void s390x_translate_init(void); @@ -352,21 +358,10 @@ static inline void cpu_set_tls(CPUS390XState *env, target_ulong newtls) #include "exec/exec-all.h" -#ifdef CONFIG_USER_ONLY - -#define EXCP_OPEX 1 /* operation exception (sigill) */ -#define EXCP_SVC 2 /* supervisor call (syscall) */ -#define EXCP_ADDR 5 /* addressing exception */ -#define EXCP_SPEC 6 /* specification exception */ - -#else - #define EXCP_EXT 1 /* external interrupt */ #define EXCP_SVC 2 /* supervisor call (syscall) */ #define EXCP_PGM 3 /* program interruption */ -#endif /* CONFIG_USER_ONLY */ - #define INTERRUPT_EXT (1 << 0) #define INTERRUPT_TOD (1 << 1) #define INTERRUPT_CPUTIMER (1 << 2) @@ -532,9 +527,9 @@ typedef struct LowCore uint32_t ext_params; /* 0x080 */ uint16_t cpu_addr; /* 0x084 */ uint16_t ext_int_code; /* 0x086 */ - uint16_t svc_ilc; /* 0x088 */ + uint16_t svc_ilen; /* 0x088 */ uint16_t svc_code; /* 0x08a */ - uint16_t pgm_ilc; /* 0x08c */ + uint16_t pgm_ilen; /* 0x08c */ uint16_t pgm_code; /* 0x08e */ uint32_t data_exc_code; /* 0x090 */ uint16_t mon_class_num; /* 0x094 */ @@ -924,6 +919,6 @@ uint32_t set_cc_nz_f32(float32 v); uint32_t set_cc_nz_f64(float64 v); /* misc_helper.c */ -void program_interrupt(CPUS390XState *env, uint32_t code, int ilc); +void program_interrupt(CPUS390XState *env, uint32_t code, int ilen); #endif diff --git a/target-s390x/helper.c b/target-s390x/helper.c index 7dc4d46eac1fcf4adc3f3fcae79b22087855ae6f..9a132e6d2c4521f340dd467bf93e411c86d4582f 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -99,10 +99,10 @@ void do_interrupt(CPUS390XState *env) int cpu_s390x_handle_mmu_fault(CPUS390XState *env, target_ulong address, int rw, int mmu_idx) { - /* fprintf(stderr, "%s: address 0x%lx rw %d mmu_idx %d\n", - __func__, address, rw, mmu_idx); */ - env->exception_index = EXCP_ADDR; - /* FIXME: find out how this works on a real machine */ + env->exception_index = EXCP_PGM; + env->int_pgm_code = PGM_ADDRESSING; + /* On real machines this value is dropped into LowMem. Since this + is userland, simply put this someplace that cpu_loop can find it. */ env->__excp_addr = address; return 1; } @@ -111,11 +111,11 @@ int cpu_s390x_handle_mmu_fault(CPUS390XState *env, target_ulong address, /* Ensure to exit the TB after this call! */ static void trigger_pgm_exception(CPUS390XState *env, uint32_t code, - uint32_t ilc) + uint32_t ilen) { env->exception_index = EXCP_PGM; env->int_pgm_code = code; - env->int_pgm_ilc = ilc; + env->int_pgm_ilen = ilen; } static int trans_bits(CPUS390XState *env, uint64_t mode) @@ -143,30 +143,30 @@ static int trans_bits(CPUS390XState *env, uint64_t mode) static void trigger_prot_fault(CPUS390XState *env, target_ulong vaddr, uint64_t mode) { - int ilc = ILC_LATER_INC_2; + int ilen = ILEN_LATER_INC; int bits = trans_bits(env, mode) | 4; DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __func__, vaddr, bits); stq_phys(env->psa + offsetof(LowCore, trans_exc_code), vaddr | bits); - trigger_pgm_exception(env, PGM_PROTECTION, ilc); + trigger_pgm_exception(env, PGM_PROTECTION, ilen); } static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr, uint32_t type, uint64_t asc, int rw) { - int ilc = ILC_LATER; + int ilen = ILEN_LATER; int bits = trans_bits(env, asc); + /* Code accesses have an undefined ilc. */ if (rw == 2) { - /* code has is undefined ilc */ - ilc = 2; + ilen = 2; } DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __func__, vaddr, bits); stq_phys(env->psa + offsetof(LowCore, trans_exc_code), vaddr | bits); - trigger_pgm_exception(env, type, ilc); + trigger_pgm_exception(env, type, ilen); } static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, @@ -406,7 +406,7 @@ int cpu_s390x_handle_mmu_fault(CPUS390XState *env, target_ulong orig_vaddr, if (raddr > (ram_size + virtio_size)) { DPRINTF("%s: aaddr %" PRIx64 " > ram_size %" PRIx64 "\n", __func__, (uint64_t)aaddr, (uint64_t)ram_size); - trigger_pgm_exception(env, PGM_ADDRESSING, ILC_LATER); + trigger_pgm_exception(env, PGM_ADDRESSING, ILEN_LATER); return 1; } @@ -480,9 +480,9 @@ static void do_svc_interrupt(CPUS390XState *env) lowcore = cpu_physical_memory_map(env->psa, &len, 1); lowcore->svc_code = cpu_to_be16(env->int_svc_code); - lowcore->svc_ilc = cpu_to_be16(env->int_svc_ilc); + 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_ilc)); + 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); @@ -496,28 +496,26 @@ static void do_program_interrupt(CPUS390XState *env) uint64_t mask, addr; LowCore *lowcore; hwaddr len = TARGET_PAGE_SIZE; - int ilc = env->int_pgm_ilc; + int ilen = env->int_pgm_ilen; - switch (ilc) { - case ILC_LATER: - ilc = get_ilc(cpu_ldub_code(env, env->psw.addr)); - break; - case ILC_LATER_INC: - ilc = get_ilc(cpu_ldub_code(env, env->psw.addr)); - env->psw.addr += ilc * 2; + switch (ilen) { + case ILEN_LATER: + ilen = get_ilen(cpu_ldub_code(env, env->psw.addr)); break; - case ILC_LATER_INC_2: - ilc = get_ilc(cpu_ldub_code(env, env->psw.addr)) * 2; - env->psw.addr += ilc; + 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 ilc=%d\n", - __func__, env->int_pgm_code, ilc); + qemu_log_mask(CPU_LOG_INT, "%s: code=0x%x ilen=%d\n", + __func__, env->int_pgm_code, ilen); lowcore = cpu_physical_memory_map(env->psa, &len, 1); - lowcore->pgm_ilc = cpu_to_be16(ilc); + 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); @@ -527,7 +525,7 @@ static void do_program_interrupt(CPUS390XState *env) cpu_physical_memory_unmap(lowcore, len, 1, len); DPRINTF("%s: %x %x %" PRIx64 " %" PRIx64 "\n", __func__, - env->int_pgm_code, ilc, env->psw.mask, + env->int_pgm_code, ilen, env->psw.mask, env->psw.addr); load_psw(env, mask, addr); diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index bed21e6e1cae0a6f249935bce419ef3a191f4e10..7eb3790b40eb642279fd3e13a0c2255c2f490ae3 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -594,7 +594,7 @@ uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1, HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff); env->psw.addr = ret - 4; env->int_svc_code = (insn | v1) & 0xff; - env->int_svc_ilc = 4; + env->int_svc_ilen = 4; helper_exception(env, EXCP_SVC); } else if ((insn & 0xff00) == 0xbf00) { uint32_t insn2, r1, r3, b2, d2; diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 70f9739685d370cab69dd12ba140a0dd7cf2fdb0..2aa1ed0b5e954e65b32a9e5f4aa3c5d8a804c81d 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -41,7 +41,7 @@ #define HELPER_LOG(x...) #endif -/* raise an exception */ +/* Raise an exception statically from a TB. */ void HELPER(exception)(CPUS390XState *env, uint32_t excp) { HELPER_LOG("%s: exception %d\n", __func__, excp); @@ -50,7 +50,7 @@ void HELPER(exception)(CPUS390XState *env, uint32_t excp) } #ifndef CONFIG_USER_ONLY -void program_interrupt(CPUS390XState *env, uint32_t code, int ilc) +void program_interrupt(CPUS390XState *env, uint32_t code, int ilen) { qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n", env->psw.addr); @@ -61,7 +61,7 @@ void program_interrupt(CPUS390XState *env, uint32_t code, int ilc) #endif } else { env->int_pgm_code = code; - env->int_pgm_ilc = ilc; + env->int_pgm_ilen = ilen; env->exception_index = EXCP_PGM; cpu_loop_exit(env); } @@ -105,7 +105,7 @@ uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem, } if (r) { - program_interrupt(env, PGM_OPERATION, ILC_LATER_INC); + program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC); } return r; diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 6761889e1f6feaa91ae9335ce0af0fd168aff166..076bb7f5fe42dd49ad2baed192099d51711262bc 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -18,7 +18,6 @@ * License along with this library; if not, see . */ -/* #define DEBUG_ILLEGAL_INSTRUCTIONS */ /* #define DEBUG_INLINE_BRANCHES */ #define S390X_DEBUG_DISAS /* #define S390X_DEBUG_DISAS_VERBOSE */ @@ -338,105 +337,52 @@ static inline int get_mem_index(DisasContext *s) } } -static inline void gen_debug(DisasContext *s) +static void gen_exception(int excp) { - TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG); - update_psw_addr(s); - gen_op_calc_cc(s); - gen_helper_exception(cpu_env, tmp); - tcg_temp_free_i32(tmp); - s->is_jmp = DISAS_EXCP; -} - -#ifdef CONFIG_USER_ONLY - -static void gen_illegal_opcode(CPUS390XState *env, DisasContext *s, int ilc) -{ - TCGv_i32 tmp = tcg_const_i32(EXCP_SPEC); - update_psw_addr(s); - gen_op_calc_cc(s); + TCGv_i32 tmp = tcg_const_i32(excp); gen_helper_exception(cpu_env, tmp); tcg_temp_free_i32(tmp); - s->is_jmp = DISAS_EXCP; } -#else /* CONFIG_USER_ONLY */ - -static void debug_print_inst(CPUS390XState *env, DisasContext *s, int ilc) -{ -#ifdef DEBUG_ILLEGAL_INSTRUCTIONS - uint64_t inst = 0; - - switch (ilc & 3) { - case 1: - inst = ld_code2(env, s->pc); - break; - case 2: - inst = ld_code4(env, s->pc); - break; - case 3: - inst = ld_code6(env, s->pc); - break; - } - - fprintf(stderr, "Illegal instruction [%d at %016" PRIx64 "]: 0x%016" - PRIx64 "\n", ilc, s->pc, inst); -#endif -} - -static void gen_program_exception(CPUS390XState *env, DisasContext *s, int ilc, - int code) +static void gen_program_exception(DisasContext *s, int code) { TCGv_i32 tmp; - debug_print_inst(env, s, ilc); - - /* remember what pgm exeption this was */ + /* Remember what pgm exeption this was. */ tmp = tcg_const_i32(code); tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_code)); tcg_temp_free_i32(tmp); - tmp = tcg_const_i32(ilc); - tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_ilc)); + tmp = tcg_const_i32(s->next_pc - s->pc); + tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_ilen)); tcg_temp_free_i32(tmp); - /* advance past instruction */ - s->pc += (ilc * 2); + /* Advance past instruction. */ + s->pc = s->next_pc; update_psw_addr(s); - /* save off cc */ + /* Save off cc. */ gen_op_calc_cc(s); - /* trigger exception */ - tmp = tcg_const_i32(EXCP_PGM); - gen_helper_exception(cpu_env, tmp); - tcg_temp_free_i32(tmp); + /* Trigger exception. */ + gen_exception(EXCP_PGM); - /* end TB here */ + /* End TB here. */ s->is_jmp = DISAS_EXCP; } - -static void gen_illegal_opcode(CPUS390XState *env, DisasContext *s, int ilc) +static inline void gen_illegal_opcode(DisasContext *s) { - gen_program_exception(env, s, ilc, PGM_SPECIFICATION); + gen_program_exception(s, PGM_SPECIFICATION); } -static void gen_privileged_exception(CPUS390XState *env, DisasContext *s, - int ilc) -{ - gen_program_exception(env, s, ilc, PGM_PRIVILEGED); -} - -static void check_privileged(CPUS390XState *env, DisasContext *s, int ilc) +static inline void check_privileged(DisasContext *s) { if (s->tb->flags & (PSW_MASK_PSTATE >> 32)) { - gen_privileged_exception(env, s, ilc); + gen_program_exception(s, PGM_PRIVILEGED); } } -#endif /* CONFIG_USER_ONLY */ - static TCGv_i64 get_address(DisasContext *s, int x2, int b2, int d2) { TCGv_i64 tmp; @@ -1769,7 +1715,7 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, break; default: LOG_DISAS("illegal e3 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 3); + gen_illegal_opcode(s); break; } tcg_temp_free_i64(addr); @@ -1794,7 +1740,7 @@ static void disas_e5(CPUS390XState *env, DisasContext* s, uint64_t insn) break; default: LOG_DISAS("illegal e5 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 3); + gen_illegal_opcode(s); break; } @@ -1809,7 +1755,6 @@ static void disas_eb(CPUS390XState *env, DisasContext *s, int op, int r1, TCGv_i64 tmp, tmp2, tmp3, tmp4; TCGv_i32 tmp32_1, tmp32_2; int i, stm_len; - int ilc = 3; LOG_DISAS("disas_eb: op 0x%x r1 %d r3 %d b2 %d d2 0x%x\n", op, r1, r3, b2, d2); @@ -1947,7 +1892,7 @@ do_mh: #ifndef CONFIG_USER_ONLY case 0x2f: /* LCTLG R1,R3,D2(B2) [RSE] */ /* Load Control */ - check_privileged(env, s, ilc); + check_privileged(s); tmp = get_address(s, 0, b2, d2); tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r3); @@ -1959,7 +1904,7 @@ do_mh: break; case 0x25: /* STCTG R1,R3,D2(B2) [RSE] */ /* Store Control */ - check_privileged(env, s, ilc); + check_privileged(s); tmp = get_address(s, 0, b2, d2); tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r3); @@ -2036,7 +1981,7 @@ do_mh: break; default: LOG_DISAS("illegal eb operation 0x%x\n", op); - gen_illegal_opcode(env, s, ilc); + gen_illegal_opcode(s); break; } } @@ -2156,7 +2101,7 @@ static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, break; default: LOG_DISAS("illegal ed operation 0x%x\n", op); - gen_illegal_opcode(env, s, 3); + gen_illegal_opcode(s); return; } tcg_temp_free_i32(tmp_r1); @@ -2313,7 +2258,7 @@ static void disas_a5(CPUS390XState *env, DisasContext *s, int op, int r1, break; default: LOG_DISAS("illegal a5 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 2); + gen_illegal_opcode(s); return; } } @@ -2451,7 +2396,7 @@ static void disas_a7(CPUS390XState *env, DisasContext *s, int op, int r1, break; default: LOG_DISAS("illegal a7 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 2); + gen_illegal_opcode(s); return; } } @@ -2462,7 +2407,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, TCGv_i64 tmp, tmp2, tmp3; TCGv_i32 tmp32_1, tmp32_2, tmp32_3; int r1, r2; - int ilc = 2; #ifndef CONFIG_USER_ONLY int r3, d2, b2; #endif @@ -2556,7 +2500,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, #ifndef CONFIG_USER_ONLY case 0x02: /* STIDP D2(B2) [S] */ /* Store CPU ID */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); @@ -2565,7 +2509,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x04: /* SCK D2(B2) [S] */ /* Set Clock */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); @@ -2584,7 +2528,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x06: /* SCKC D2(B2) [S] */ /* Set Clock Comparator */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); @@ -2593,7 +2537,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x07: /* STCKC D2(B2) [S] */ /* Store Clock Comparator */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); @@ -2602,7 +2546,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x08: /* SPT D2(B2) [S] */ /* Set CPU Timer */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); @@ -2611,7 +2555,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x09: /* STPT D2(B2) [S] */ /* Store CPU Timer */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); @@ -2620,7 +2564,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x0a: /* SPKA D2(B2) [S] */ /* Set PSW Key from Address */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); tmp2 = tcg_temp_new_i64(); @@ -2632,12 +2576,12 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x0d: /* PTLB [S] */ /* Purge TLB */ - check_privileged(env, s, ilc); + check_privileged(s); gen_helper_ptlb(cpu_env); break; case 0x10: /* SPX D2(B2) [S] */ /* Set Prefix Register */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); @@ -2646,7 +2590,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x11: /* STPX D2(B2) [S] */ /* Store Prefix */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); tmp2 = tcg_temp_new_i64(); @@ -2657,7 +2601,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x12: /* STAP D2(B2) [S] */ /* Store CPU Address */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); tmp2 = tcg_temp_new_i64(); @@ -2671,7 +2615,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x21: /* IPTE R1,R2 [RRE] */ /* Invalidate PTE */ - check_privileged(env, s, ilc); + check_privileged(s); r1 = (insn >> 4) & 0xf; r2 = insn & 0xf; tmp = load_reg(r1); @@ -2682,7 +2626,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x29: /* ISKE R1,R2 [RRE] */ /* Insert Storage Key Extended */ - check_privileged(env, s, ilc); + check_privileged(s); r1 = (insn >> 4) & 0xf; r2 = insn & 0xf; tmp = load_reg(r2); @@ -2694,7 +2638,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x2a: /* RRBE R1,R2 [RRE] */ /* Set Storage Key Extended */ - check_privileged(env, s, ilc); + check_privileged(s); r1 = (insn >> 4) & 0xf; r2 = insn & 0xf; tmp32_1 = load_reg32(r1); @@ -2706,7 +2650,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x2b: /* SSKE R1,R2 [RRE] */ /* Set Storage Key Extended */ - check_privileged(env, s, ilc); + check_privileged(s); r1 = (insn >> 4) & 0xf; r2 = insn & 0xf; tmp32_1 = load_reg32(r1); @@ -2717,12 +2661,12 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x34: /* STCH ? */ /* Store Subchannel */ - check_privileged(env, s, ilc); + check_privileged(s); gen_op_movi_cc(s, 3); break; case 0x46: /* STURA R1,R2 [RRE] */ /* Store Using Real Address */ - check_privileged(env, s, ilc); + check_privileged(s); r1 = (insn >> 4) & 0xf; r2 = insn & 0xf; tmp32_1 = load_reg32(r1); @@ -2734,7 +2678,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x50: /* CSP R1,R2 [RRE] */ /* Compare And Swap And Purge */ - check_privileged(env, s, ilc); + check_privileged(s); r1 = (insn >> 4) & 0xf; r2 = insn & 0xf; tmp32_1 = tcg_const_i32(r1); @@ -2746,7 +2690,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x5f: /* CHSC ? */ /* Channel Subsystem Call */ - check_privileged(env, s, ilc); + check_privileged(s); gen_op_movi_cc(s, 3); break; case 0x78: /* STCKE D2(B2) [S] */ @@ -2760,19 +2704,19 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x79: /* SACF D2(B2) [S] */ /* Set Address Space Control Fast */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); gen_helper_sacf(cpu_env, tmp); tcg_temp_free_i64(tmp); /* addressing mode has changed, so end the block */ - s->pc += ilc * 2; + s->pc = s->next_pc; update_psw_addr(s); s->is_jmp = DISAS_JUMP; break; case 0x7d: /* STSI D2,(B2) [S] */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); tmp32_1 = load_reg32(0); @@ -2798,7 +2742,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0xb1: /* STFL D2(B2) [S] */ /* Store Facility List (CPU features) at 200 */ - check_privileged(env, s, ilc); + check_privileged(s); tmp2 = tcg_const_i64(0xc0000000); tmp = tcg_const_i64(200); tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s)); @@ -2807,7 +2751,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0xb2: /* LPSWE D2(B2) [S] */ /* Load PSW Extended */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); tmp2 = tcg_temp_new_i64(); @@ -2824,7 +2768,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x20: /* SERVC R1,R2 [RRE] */ /* SCLP Service call (PV hypercall) */ - check_privileged(env, s, ilc); + check_privileged(s); potential_page_fault(s); tmp32_1 = load_reg32(r2); tmp = load_reg(r1); @@ -2836,7 +2780,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, #endif default: LOG_DISAS("illegal b2 operation 0x%x\n", op); - gen_illegal_opcode(env, s, ilc); + gen_illegal_opcode(s); break; } } @@ -3112,7 +3056,7 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, break; default: LOG_DISAS("illegal b3 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 2); + gen_illegal_opcode(s); break; } @@ -3419,7 +3363,7 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, break; default: LOG_DISAS("illegal b9 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 2); + gen_illegal_opcode(s); break; } } @@ -3525,7 +3469,7 @@ static void disas_c0(CPUS390XState *env, DisasContext *s, int op, int r1, int i2 break; default: LOG_DISAS("illegal c0 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 3); + gen_illegal_opcode(s); break; } } @@ -3559,7 +3503,7 @@ static void disas_c2(CPUS390XState *env, DisasContext *s, int op, int r1, break; default: LOG_DISAS("illegal c2 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 3); + gen_illegal_opcode(s); break; } } @@ -3589,14 +3533,11 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) uint64_t insn; int op, r1, r2, r3, d1, d2, x2, b1, b2, i, i2, r1b; TCGv_i32 vl; - int ilc; int l1; opc = cpu_ldub_code(env, s->pc); LOG_DISAS("opc 0x%x\n", opc); - ilc = get_ilc(opc); - switch (opc) { #ifndef CONFIG_USER_ONLY case 0x01: /* SAM */ @@ -3649,15 +3590,13 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) update_psw_addr(s); gen_op_calc_cc(s); tmp32_1 = tcg_const_i32(i); - tmp32_2 = tcg_const_i32(ilc * 2); - tmp32_3 = tcg_const_i32(EXCP_SVC); + tmp32_2 = tcg_const_i32(s->next_pc - s->pc); tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, int_svc_code)); - tcg_gen_st_i32(tmp32_2, cpu_env, offsetof(CPUS390XState, int_svc_ilc)); - gen_helper_exception(cpu_env, tmp32_3); + tcg_gen_st_i32(tmp32_2, cpu_env, offsetof(CPUS390XState, int_svc_ilen)); + gen_exception(EXCP_SVC); s->is_jmp = DISAS_EXCP; tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); break; case 0xd: /* BASR R1,R2 [RR] */ insn = ld_code2(env, s->pc); @@ -4148,7 +4087,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) #ifndef CONFIG_USER_ONLY case 0x80: /* SSM D2(B2) [S] */ /* Set System Mask */ - check_privileged(env, s, ilc); + check_privileged(s); insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); @@ -4164,7 +4103,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) break; case 0x82: /* LPSW D2(B2) [S] */ /* Load PSW */ - check_privileged(env, s, ilc); + check_privileged(s); insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); @@ -4184,7 +4123,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) break; case 0x83: /* DIAG R1,R3,D2 [RS] */ /* Diagnose call (KVM hypercall) */ - check_privileged(env, s, ilc); + check_privileged(s); potential_page_fault(s); insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); @@ -4402,7 +4341,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) #ifndef CONFIG_USER_ONLY case 0xac: /* STNSM D1(B1),I2 [SI] */ case 0xad: /* STOSM D1(B1),I2 [SI] */ - check_privileged(env, s, ilc); + check_privileged(s); insn = ld_code4(env, s->pc); tmp = decode_si(s, insn, &i2, &b1, &d1); tmp2 = tcg_temp_new_i64(); @@ -4418,7 +4357,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp2); break; case 0xae: /* SIGP R1,R3,D2(B2) [RS] */ - check_privileged(env, s, ilc); + check_privileged(s); insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); @@ -4432,7 +4371,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); break; case 0xb1: /* LRA R1,D2(X2, B2) [RX] */ - check_privileged(env, s, ilc); + check_privileged(s); insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); tmp32_1 = tcg_const_i32(r1); @@ -4476,7 +4415,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) #ifndef CONFIG_USER_ONLY case 0xb6: /* STCTL R1,R3,D2(B2) [RS] */ /* Store Control */ - check_privileged(env, s, ilc); + check_privileged(s); insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); @@ -4490,7 +4429,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) break; case 0xb7: /* LCTL R1,R3,D2(B2) [RS] */ /* Load Control */ - check_privileged(env, s, ilc); + check_privileged(s); insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); @@ -4674,7 +4613,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) #ifndef CONFIG_USER_ONLY case 0xda: /* MVCP D1(R1,B1),D2(B2),R3 [SS] */ case 0xdb: /* MVCS D1(R1,B1),D2(B2),R3 [SS] */ - check_privileged(env, s, ilc); + check_privileged(s); potential_page_fault(s); insn = ld_code6(env, s->pc); r1 = (insn >> 36) & 0xf; @@ -4712,7 +4651,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) #ifndef CONFIG_USER_ONLY case 0xe5: /* Test Protection */ - check_privileged(env, s, ilc); + check_privileged(s); insn = ld_code6(env, s->pc); debug_insn(insn); disas_e5(env, s, insn); @@ -4742,7 +4681,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) break; default: qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%x\n", opc); - gen_illegal_opcode(env, s, ilc); + gen_illegal_opcode(s); break; } } @@ -5273,19 +5212,22 @@ static const DisasInsn *extract_insn(CPUS390XState *env, DisasContext *s, DisasFields *f) { uint64_t insn, pc = s->pc; - int op, op2; + int op, op2, ilen; const DisasInsn *info; insn = ld_code2(env, pc); op = (insn >> 8) & 0xff; - switch (get_ilc(op)) { - case 1: + ilen = get_ilen(op); + s->next_pc = s->pc + ilen; + + switch (ilen) { + case 2: insn = insn << 48; break; - case 2: + case 4: insn = ld_code4(env, pc) << 32; break; - case 3: + case 6: insn = (insn << 48) | (ld_code4(env, pc + 2) << 16); break; default: @@ -5361,9 +5303,6 @@ static ExitStatus translate_one(CPUS390XState *env, DisasContext *s) insn = extract_insn(env, s, &f); - /* Instruction length is encoded in the opcode */ - s->next_pc = s->pc + get_ilc(f.op) * 2; - /* If not found, try the old interpreter. This includes ILLOPC. */ if (insn == NULL) { disas_s390_insn(env, s); @@ -5452,6 +5391,7 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, int num_insns, max_insns; CPUBreakpoint *bp; ExitStatus status; + bool do_debug; pc_start = tb->pc; @@ -5463,7 +5403,7 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, dc.tb = tb; dc.pc = pc_start; dc.cc_op = CC_OP_DYNAMIC; - dc.singlestep_enabled = env->singlestep_enabled; + do_debug = dc.singlestep_enabled = env->singlestep_enabled; dc.is_jmp = DISAS_NEXT; gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; @@ -5479,14 +5419,6 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, gen_icount_start(); do { - if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { - QTAILQ_FOREACH(bp, &env->breakpoints, entry) { - if (bp->pc == dc.pc) { - gen_debug(&dc); - break; - } - } - } if (search_pc) { j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { @@ -5508,7 +5440,19 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, tcg_gen_debug_insn_start(dc.pc); } - status = translate_one(env, &dc); + status = NO_EXIT; + if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { + QTAILQ_FOREACH(bp, &env->breakpoints, entry) { + if (bp->pc == dc.pc) { + status = EXIT_PC_STALE; + do_debug = true; + break; + } + } + } + if (status == NO_EXIT) { + status = translate_one(env, &dc); + } /* If we reach a page boundary, are single stepping, or exhaust instruction count, stop generation. */ @@ -5541,8 +5485,8 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, so make sure the cc op type is in env */ gen_op_set_cc_op(&dc); } - if (env->singlestep_enabled) { - gen_debug(&dc); + if (do_debug) { + gen_exception(EXCP_DEBUG); } else { /* Generate the return instruction */ tcg_gen_exit_tb(0);