target-s390: Reorg exception handling

Make the user path more like the system path.  Prepare for more kinds
of runtime exceptions.  Rename ILC to ILEN to make it clear that we
want to pass around a full instruction length, rather than a "code"
that happens to be stored one bit left in a larger field.

Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
Richard Henderson 2012-09-14 19:31:57 -07:00
parent 3fde06f5fb
commit d5a103cd6e
7 changed files with 242 additions and 261 deletions

View file

@ -2933,71 +2933,115 @@ void cpu_loop(CPUAlphaState *env)
#ifdef TARGET_S390X #ifdef TARGET_S390X
void cpu_loop(CPUS390XState *env) void cpu_loop(CPUS390XState *env)
{ {
int trapnr; int trapnr, n, sig;
target_siginfo_t info; target_siginfo_t info;
target_ulong addr;
while (1) { while (1) {
trapnr = cpu_s390x_exec (env); trapnr = cpu_s390x_exec(env);
switch (trapnr) { switch (trapnr) {
case EXCP_INTERRUPT: case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */ /* Just indicate that signals should be handled asap. */
break; 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);
}
}
break;
case EXCP_SVC: case EXCP_SVC:
{ n = env->int_svc_code;
int n = env->int_svc_code; if (!n) {
if (!n) { /* syscalls > 255 */
/* syscalls > 255 */ n = env->regs[1];
n = env->regs[1]; }
} env->psw.addr += env->int_svc_ilen;
env->psw.addr += env->int_svc_ilc; env->regs[2] = do_syscall(env, n, env->regs[2], env->regs[3],
env->regs[2] = do_syscall(env, n, env->regs[4], env->regs[5],
env->regs[2], env->regs[6], env->regs[7], 0, 0);
env->regs[3], break;
env->regs[4],
env->regs[5], case EXCP_DEBUG:
env->regs[6], sig = gdb_handlesig(env, TARGET_SIGTRAP);
env->regs[7], if (sig) {
0, 0); n = TARGET_TRAP_BRKPT;
goto do_signal_pc;
} }
break; break;
case EXCP_ADDR: case EXCP_PGM:
{ n = env->int_pgm_code;
info.si_signo = SIGSEGV; switch (n) {
info.si_errno = 0; 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 */ /* XXX: check env->error_code */
info.si_code = TARGET_SEGV_MAPERR; n = TARGET_SEGV_MAPERR;
info._sifields._sigfault._addr = env->__excp_addr; addr = env->__excp_addr;
queue_signal(env, info.si_signo, &info); 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; break;
case EXCP_SPEC:
{ do_signal_pc:
fprintf(stderr,"specification exception insn 0x%08x%04x\n", ldl(env->psw.addr), lduw(env->psw.addr + 4)); addr = env->psw.addr;
info.si_signo = SIGILL; do_signal:
info.si_errno = 0; info.si_signo = sig;
info.si_code = TARGET_ILL_ILLOPC; info.si_errno = 0;
info._sifields._sigfault._addr = env->__excp_addr; info.si_code = n;
queue_signal(env, info.si_signo, &info); info._sifields._sigfault._addr = addr;
} queue_signal(env, info.si_signo, &info);
break; break;
default: default:
printf ("Unhandled trap: 0x%x\n", trapnr); fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr);
cpu_dump_state(env, stderr, fprintf, 0); cpu_dump_state(env, stderr, fprintf, 0);
exit (1); exit(1);
} }
process_pending_signals (env); process_pending_signals (env);
} }

View file

@ -16,7 +16,7 @@ struct target_pt_regs {
target_psw_t psw; target_psw_t psw;
abi_ulong gprs[TARGET_NUM_GPRS]; abi_ulong gprs[TARGET_NUM_GPRS];
abi_ulong orig_gpr2; abi_ulong orig_gpr2;
unsigned short ilc; unsigned short ilen;
unsigned short trap; unsigned short trap;
}; };

View file

@ -79,10 +79,10 @@ typedef struct CPUS390XState {
uint64_t psa; uint64_t psa;
uint32_t int_pgm_code; uint32_t int_pgm_code;
uint32_t int_pgm_ilc; uint32_t int_pgm_ilen;
uint32_t int_svc_code; uint32_t int_svc_code;
uint32_t int_svc_ilc; uint32_t int_svc_ilen;
uint64_t cregs[16]; /* control registers */ 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); ((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) { switch (opc >> 6) {
case 0: case 0:
return 1; return 2;
case 1: case 1:
case 2: case 2:
return 2; return 4;
case 3: default:
return 3; return 6;
} }
return 0;
} }
#define ILC_LATER 0x20 #ifndef CONFIG_USER_ONLY
#define ILC_LATER_INC 0x21 /* In several cases of runtime exceptions, we havn't recorded the true
#define ILC_LATER_INC_2 0x22 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); S390CPU *cpu_s390x_init(const char *cpu_model);
void s390x_translate_init(void); 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" #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_EXT 1 /* external interrupt */
#define EXCP_SVC 2 /* supervisor call (syscall) */ #define EXCP_SVC 2 /* supervisor call (syscall) */
#define EXCP_PGM 3 /* program interruption */ #define EXCP_PGM 3 /* program interruption */
#endif /* CONFIG_USER_ONLY */
#define INTERRUPT_EXT (1 << 0) #define INTERRUPT_EXT (1 << 0)
#define INTERRUPT_TOD (1 << 1) #define INTERRUPT_TOD (1 << 1)
#define INTERRUPT_CPUTIMER (1 << 2) #define INTERRUPT_CPUTIMER (1 << 2)
@ -532,9 +527,9 @@ typedef struct LowCore
uint32_t ext_params; /* 0x080 */ uint32_t ext_params; /* 0x080 */
uint16_t cpu_addr; /* 0x084 */ uint16_t cpu_addr; /* 0x084 */
uint16_t ext_int_code; /* 0x086 */ uint16_t ext_int_code; /* 0x086 */
uint16_t svc_ilc; /* 0x088 */ uint16_t svc_ilen; /* 0x088 */
uint16_t svc_code; /* 0x08a */ uint16_t svc_code; /* 0x08a */
uint16_t pgm_ilc; /* 0x08c */ uint16_t pgm_ilen; /* 0x08c */
uint16_t pgm_code; /* 0x08e */ uint16_t pgm_code; /* 0x08e */
uint32_t data_exc_code; /* 0x090 */ uint32_t data_exc_code; /* 0x090 */
uint16_t mon_class_num; /* 0x094 */ 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); uint32_t set_cc_nz_f64(float64 v);
/* misc_helper.c */ /* misc_helper.c */
void program_interrupt(CPUS390XState *env, uint32_t code, int ilc); void program_interrupt(CPUS390XState *env, uint32_t code, int ilen);
#endif #endif

View file

@ -99,10 +99,10 @@ void do_interrupt(CPUS390XState *env)
int cpu_s390x_handle_mmu_fault(CPUS390XState *env, target_ulong address, int cpu_s390x_handle_mmu_fault(CPUS390XState *env, target_ulong address,
int rw, int mmu_idx) int rw, int mmu_idx)
{ {
/* fprintf(stderr, "%s: address 0x%lx rw %d mmu_idx %d\n", env->exception_index = EXCP_PGM;
__func__, address, rw, mmu_idx); */ env->int_pgm_code = PGM_ADDRESSING;
env->exception_index = EXCP_ADDR; /* On real machines this value is dropped into LowMem. Since this
/* FIXME: find out how this works on a real machine */ is userland, simply put this someplace that cpu_loop can find it. */
env->__excp_addr = address; env->__excp_addr = address;
return 1; 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! */ /* Ensure to exit the TB after this call! */
static void trigger_pgm_exception(CPUS390XState *env, uint32_t code, static void trigger_pgm_exception(CPUS390XState *env, uint32_t code,
uint32_t ilc) uint32_t ilen)
{ {
env->exception_index = EXCP_PGM; env->exception_index = EXCP_PGM;
env->int_pgm_code = code; env->int_pgm_code = code;
env->int_pgm_ilc = ilc; env->int_pgm_ilen = ilen;
} }
static int trans_bits(CPUS390XState *env, uint64_t mode) 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, static void trigger_prot_fault(CPUS390XState *env, target_ulong vaddr,
uint64_t mode) uint64_t mode)
{ {
int ilc = ILC_LATER_INC_2; int ilen = ILEN_LATER_INC;
int bits = trans_bits(env, mode) | 4; int bits = trans_bits(env, mode) | 4;
DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __func__, vaddr, bits); DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __func__, vaddr, bits);
stq_phys(env->psa + offsetof(LowCore, trans_exc_code), 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, static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr,
uint32_t type, uint64_t asc, int rw) uint32_t type, uint64_t asc, int rw)
{ {
int ilc = ILC_LATER; int ilen = ILEN_LATER;
int bits = trans_bits(env, asc); int bits = trans_bits(env, asc);
/* Code accesses have an undefined ilc. */
if (rw == 2) { if (rw == 2) {
/* code has is undefined ilc */ ilen = 2;
ilc = 2;
} }
DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __func__, vaddr, bits); DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __func__, vaddr, bits);
stq_phys(env->psa + offsetof(LowCore, trans_exc_code), 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, 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)) { if (raddr > (ram_size + virtio_size)) {
DPRINTF("%s: aaddr %" PRIx64 " > ram_size %" PRIx64 "\n", __func__, DPRINTF("%s: aaddr %" PRIx64 " > ram_size %" PRIx64 "\n", __func__,
(uint64_t)aaddr, (uint64_t)ram_size); (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; return 1;
} }
@ -480,9 +480,9 @@ static void do_svc_interrupt(CPUS390XState *env)
lowcore = cpu_physical_memory_map(env->psa, &len, 1); lowcore = cpu_physical_memory_map(env->psa, &len, 1);
lowcore->svc_code = cpu_to_be16(env->int_svc_code); 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.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); mask = be64_to_cpu(lowcore->svc_new_psw.mask);
addr = be64_to_cpu(lowcore->svc_new_psw.addr); addr = be64_to_cpu(lowcore->svc_new_psw.addr);
@ -496,28 +496,26 @@ static void do_program_interrupt(CPUS390XState *env)
uint64_t mask, addr; uint64_t mask, addr;
LowCore *lowcore; LowCore *lowcore;
hwaddr len = TARGET_PAGE_SIZE; hwaddr len = TARGET_PAGE_SIZE;
int ilc = env->int_pgm_ilc; int ilen = env->int_pgm_ilen;
switch (ilc) { switch (ilen) {
case ILC_LATER: case ILEN_LATER:
ilc = get_ilc(cpu_ldub_code(env, env->psw.addr)); ilen = get_ilen(cpu_ldub_code(env, env->psw.addr));
break; break;
case ILC_LATER_INC: case ILEN_LATER_INC:
ilc = get_ilc(cpu_ldub_code(env, env->psw.addr)); ilen = get_ilen(cpu_ldub_code(env, env->psw.addr));
env->psw.addr += ilc * 2; env->psw.addr += ilen;
break;
case ILC_LATER_INC_2:
ilc = get_ilc(cpu_ldub_code(env, env->psw.addr)) * 2;
env->psw.addr += ilc;
break; break;
default:
assert(ilen == 2 || ilen == 4 || ilen == 6);
} }
qemu_log_mask(CPU_LOG_INT, "%s: code=0x%x ilc=%d\n", qemu_log_mask(CPU_LOG_INT, "%s: code=0x%x ilen=%d\n",
__func__, env->int_pgm_code, ilc); __func__, env->int_pgm_code, ilen);
lowcore = cpu_physical_memory_map(env->psa, &len, 1); 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->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.mask = cpu_to_be64(get_psw_mask(env));
lowcore->program_old_psw.addr = cpu_to_be64(env->psw.addr); 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); cpu_physical_memory_unmap(lowcore, len, 1, len);
DPRINTF("%s: %x %x %" PRIx64 " %" PRIx64 "\n", __func__, 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); env->psw.addr);
load_psw(env, mask, addr); load_psw(env, mask, addr);

View file

@ -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); HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff);
env->psw.addr = ret - 4; env->psw.addr = ret - 4;
env->int_svc_code = (insn | v1) & 0xff; env->int_svc_code = (insn | v1) & 0xff;
env->int_svc_ilc = 4; env->int_svc_ilen = 4;
helper_exception(env, EXCP_SVC); helper_exception(env, EXCP_SVC);
} else if ((insn & 0xff00) == 0xbf00) { } else if ((insn & 0xff00) == 0xbf00) {
uint32_t insn2, r1, r3, b2, d2; uint32_t insn2, r1, r3, b2, d2;

View file

@ -41,7 +41,7 @@
#define HELPER_LOG(x...) #define HELPER_LOG(x...)
#endif #endif
/* raise an exception */ /* Raise an exception statically from a TB. */
void HELPER(exception)(CPUS390XState *env, uint32_t excp) void HELPER(exception)(CPUS390XState *env, uint32_t excp)
{ {
HELPER_LOG("%s: exception %d\n", __func__, 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 #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", qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
env->psw.addr); env->psw.addr);
@ -61,7 +61,7 @@ void program_interrupt(CPUS390XState *env, uint32_t code, int ilc)
#endif #endif
} else { } else {
env->int_pgm_code = code; env->int_pgm_code = code;
env->int_pgm_ilc = ilc; env->int_pgm_ilen = ilen;
env->exception_index = EXCP_PGM; env->exception_index = EXCP_PGM;
cpu_loop_exit(env); cpu_loop_exit(env);
} }
@ -105,7 +105,7 @@ uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem,
} }
if (r) { if (r) {
program_interrupt(env, PGM_OPERATION, ILC_LATER_INC); program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC);
} }
return r; return r;

View file

@ -18,7 +18,6 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/ */
/* #define DEBUG_ILLEGAL_INSTRUCTIONS */
/* #define DEBUG_INLINE_BRANCHES */ /* #define DEBUG_INLINE_BRANCHES */
#define S390X_DEBUG_DISAS #define S390X_DEBUG_DISAS
/* #define S390X_DEBUG_DISAS_VERBOSE */ /* #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); TCGv_i32 tmp = tcg_const_i32(excp);
update_psw_addr(s);
gen_op_calc_cc(s);
gen_helper_exception(cpu_env, tmp); gen_helper_exception(cpu_env, tmp);
tcg_temp_free_i32(tmp); tcg_temp_free_i32(tmp);
s->is_jmp = DISAS_EXCP;
} }
#ifdef CONFIG_USER_ONLY static void gen_program_exception(DisasContext *s, int code)
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);
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)
{ {
TCGv_i32 tmp; 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); tmp = tcg_const_i32(code);
tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_code)); tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_code));
tcg_temp_free_i32(tmp); tcg_temp_free_i32(tmp);
tmp = tcg_const_i32(ilc); tmp = tcg_const_i32(s->next_pc - s->pc);
tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_ilc)); tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_ilen));
tcg_temp_free_i32(tmp); tcg_temp_free_i32(tmp);
/* advance past instruction */ /* Advance past instruction. */
s->pc += (ilc * 2); s->pc = s->next_pc;
update_psw_addr(s); update_psw_addr(s);
/* save off cc */ /* Save off cc. */
gen_op_calc_cc(s); gen_op_calc_cc(s);
/* trigger exception */ /* Trigger exception. */
tmp = tcg_const_i32(EXCP_PGM); gen_exception(EXCP_PGM);
gen_helper_exception(cpu_env, tmp);
tcg_temp_free_i32(tmp);
/* end TB here */ /* End TB here. */
s->is_jmp = DISAS_EXCP; s->is_jmp = DISAS_EXCP;
} }
static inline void gen_illegal_opcode(DisasContext *s)
static void gen_illegal_opcode(CPUS390XState *env, DisasContext *s, int ilc)
{ {
gen_program_exception(env, s, ilc, PGM_SPECIFICATION); gen_program_exception(s, PGM_SPECIFICATION);
} }
static void gen_privileged_exception(CPUS390XState *env, DisasContext *s, static inline void check_privileged(DisasContext *s)
int ilc)
{
gen_program_exception(env, s, ilc, PGM_PRIVILEGED);
}
static void check_privileged(CPUS390XState *env, DisasContext *s, int ilc)
{ {
if (s->tb->flags & (PSW_MASK_PSTATE >> 32)) { 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) static TCGv_i64 get_address(DisasContext *s, int x2, int b2, int d2)
{ {
TCGv_i64 tmp; TCGv_i64 tmp;
@ -1769,7 +1715,7 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1,
break; break;
default: default:
LOG_DISAS("illegal e3 operation 0x%x\n", op); LOG_DISAS("illegal e3 operation 0x%x\n", op);
gen_illegal_opcode(env, s, 3); gen_illegal_opcode(s);
break; break;
} }
tcg_temp_free_i64(addr); tcg_temp_free_i64(addr);
@ -1794,7 +1740,7 @@ static void disas_e5(CPUS390XState *env, DisasContext* s, uint64_t insn)
break; break;
default: default:
LOG_DISAS("illegal e5 operation 0x%x\n", op); LOG_DISAS("illegal e5 operation 0x%x\n", op);
gen_illegal_opcode(env, s, 3); gen_illegal_opcode(s);
break; break;
} }
@ -1809,7 +1755,6 @@ static void disas_eb(CPUS390XState *env, DisasContext *s, int op, int r1,
TCGv_i64 tmp, tmp2, tmp3, tmp4; TCGv_i64 tmp, tmp2, tmp3, tmp4;
TCGv_i32 tmp32_1, tmp32_2; TCGv_i32 tmp32_1, tmp32_2;
int i, stm_len; int i, stm_len;
int ilc = 3;
LOG_DISAS("disas_eb: op 0x%x r1 %d r3 %d b2 %d d2 0x%x\n", LOG_DISAS("disas_eb: op 0x%x r1 %d r3 %d b2 %d d2 0x%x\n",
op, r1, r3, b2, d2); op, r1, r3, b2, d2);
@ -1947,7 +1892,7 @@ do_mh:
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
case 0x2f: /* LCTLG R1,R3,D2(B2) [RSE] */ case 0x2f: /* LCTLG R1,R3,D2(B2) [RSE] */
/* Load Control */ /* Load Control */
check_privileged(env, s, ilc); check_privileged(s);
tmp = get_address(s, 0, b2, d2); tmp = get_address(s, 0, b2, d2);
tmp32_1 = tcg_const_i32(r1); tmp32_1 = tcg_const_i32(r1);
tmp32_2 = tcg_const_i32(r3); tmp32_2 = tcg_const_i32(r3);
@ -1959,7 +1904,7 @@ do_mh:
break; break;
case 0x25: /* STCTG R1,R3,D2(B2) [RSE] */ case 0x25: /* STCTG R1,R3,D2(B2) [RSE] */
/* Store Control */ /* Store Control */
check_privileged(env, s, ilc); check_privileged(s);
tmp = get_address(s, 0, b2, d2); tmp = get_address(s, 0, b2, d2);
tmp32_1 = tcg_const_i32(r1); tmp32_1 = tcg_const_i32(r1);
tmp32_2 = tcg_const_i32(r3); tmp32_2 = tcg_const_i32(r3);
@ -2036,7 +1981,7 @@ do_mh:
break; break;
default: default:
LOG_DISAS("illegal eb operation 0x%x\n", op); LOG_DISAS("illegal eb operation 0x%x\n", op);
gen_illegal_opcode(env, s, ilc); gen_illegal_opcode(s);
break; break;
} }
} }
@ -2156,7 +2101,7 @@ static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1,
break; break;
default: default:
LOG_DISAS("illegal ed operation 0x%x\n", op); LOG_DISAS("illegal ed operation 0x%x\n", op);
gen_illegal_opcode(env, s, 3); gen_illegal_opcode(s);
return; return;
} }
tcg_temp_free_i32(tmp_r1); tcg_temp_free_i32(tmp_r1);
@ -2313,7 +2258,7 @@ static void disas_a5(CPUS390XState *env, DisasContext *s, int op, int r1,
break; break;
default: default:
LOG_DISAS("illegal a5 operation 0x%x\n", op); LOG_DISAS("illegal a5 operation 0x%x\n", op);
gen_illegal_opcode(env, s, 2); gen_illegal_opcode(s);
return; return;
} }
} }
@ -2451,7 +2396,7 @@ static void disas_a7(CPUS390XState *env, DisasContext *s, int op, int r1,
break; break;
default: default:
LOG_DISAS("illegal a7 operation 0x%x\n", op); LOG_DISAS("illegal a7 operation 0x%x\n", op);
gen_illegal_opcode(env, s, 2); gen_illegal_opcode(s);
return; return;
} }
} }
@ -2462,7 +2407,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op,
TCGv_i64 tmp, tmp2, tmp3; TCGv_i64 tmp, tmp2, tmp3;
TCGv_i32 tmp32_1, tmp32_2, tmp32_3; TCGv_i32 tmp32_1, tmp32_2, tmp32_3;
int r1, r2; int r1, r2;
int ilc = 2;
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
int r3, d2, b2; int r3, d2, b2;
#endif #endif
@ -2556,7 +2500,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op,
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
case 0x02: /* STIDP D2(B2) [S] */ case 0x02: /* STIDP D2(B2) [S] */
/* Store CPU ID */ /* Store CPU ID */
check_privileged(env, s, ilc); check_privileged(s);
decode_rs(s, insn, &r1, &r3, &b2, &d2); decode_rs(s, insn, &r1, &r3, &b2, &d2);
tmp = get_address(s, 0, b2, d2); tmp = get_address(s, 0, b2, d2);
potential_page_fault(s); potential_page_fault(s);
@ -2565,7 +2509,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op,
break; break;
case 0x04: /* SCK D2(B2) [S] */ case 0x04: /* SCK D2(B2) [S] */
/* Set Clock */ /* Set Clock */
check_privileged(env, s, ilc); check_privileged(s);
decode_rs(s, insn, &r1, &r3, &b2, &d2); decode_rs(s, insn, &r1, &r3, &b2, &d2);
tmp = get_address(s, 0, b2, d2); tmp = get_address(s, 0, b2, d2);
potential_page_fault(s); potential_page_fault(s);
@ -2584,7 +2528,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op,
break; break;
case 0x06: /* SCKC D2(B2) [S] */ case 0x06: /* SCKC D2(B2) [S] */
/* Set Clock Comparator */ /* Set Clock Comparator */
check_privileged(env, s, ilc); check_privileged(s);
decode_rs(s, insn, &r1, &r3, &b2, &d2); decode_rs(s, insn, &r1, &r3, &b2, &d2);
tmp = get_address(s, 0, b2, d2); tmp = get_address(s, 0, b2, d2);
potential_page_fault(s); potential_page_fault(s);
@ -2593,7 +2537,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op,
break; break;
case 0x07: /* STCKC D2(B2) [S] */ case 0x07: /* STCKC D2(B2) [S] */
/* Store Clock Comparator */ /* Store Clock Comparator */
check_privileged(env, s, ilc); check_privileged(s);
decode_rs(s, insn, &r1, &r3, &b2, &d2); decode_rs(s, insn, &r1, &r3, &b2, &d2);
tmp = get_address(s, 0, b2, d2); tmp = get_address(s, 0, b2, d2);
potential_page_fault(s); potential_page_fault(s);
@ -2602,7 +2546,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op,
break; break;
case 0x08: /* SPT D2(B2) [S] */ case 0x08: /* SPT D2(B2) [S] */
/* Set CPU Timer */ /* Set CPU Timer */
check_privileged(env, s, ilc); check_privileged(s);
decode_rs(s, insn, &r1, &r3, &b2, &d2); decode_rs(s, insn, &r1, &r3, &b2, &d2);
tmp = get_address(s, 0, b2, d2); tmp = get_address(s, 0, b2, d2);
potential_page_fault(s); potential_page_fault(s);
@ -2611,7 +2555,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op,
break; break;
case 0x09: /* STPT D2(B2) [S] */ case 0x09: /* STPT D2(B2) [S] */
/* Store CPU Timer */ /* Store CPU Timer */
check_privileged(env, s, ilc); check_privileged(s);
decode_rs(s, insn, &r1, &r3, &b2, &d2); decode_rs(s, insn, &r1, &r3, &b2, &d2);
tmp = get_address(s, 0, b2, d2); tmp = get_address(s, 0, b2, d2);
potential_page_fault(s); potential_page_fault(s);
@ -2620,7 +2564,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op,
break; break;
case 0x0a: /* SPKA D2(B2) [S] */ case 0x0a: /* SPKA D2(B2) [S] */
/* Set PSW Key from Address */ /* Set PSW Key from Address */
check_privileged(env, s, ilc); check_privileged(s);
decode_rs(s, insn, &r1, &r3, &b2, &d2); decode_rs(s, insn, &r1, &r3, &b2, &d2);
tmp = get_address(s, 0, b2, d2); tmp = get_address(s, 0, b2, d2);
tmp2 = tcg_temp_new_i64(); tmp2 = tcg_temp_new_i64();
@ -2632,12 +2576,12 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op,
break; break;
case 0x0d: /* PTLB [S] */ case 0x0d: /* PTLB [S] */
/* Purge TLB */ /* Purge TLB */
check_privileged(env, s, ilc); check_privileged(s);
gen_helper_ptlb(cpu_env); gen_helper_ptlb(cpu_env);
break; break;
case 0x10: /* SPX D2(B2) [S] */ case 0x10: /* SPX D2(B2) [S] */
/* Set Prefix Register */ /* Set Prefix Register */
check_privileged(env, s, ilc); check_privileged(s);
decode_rs(s, insn, &r1, &r3, &b2, &d2); decode_rs(s, insn, &r1, &r3, &b2, &d2);
tmp = get_address(s, 0, b2, d2); tmp = get_address(s, 0, b2, d2);
potential_page_fault(s); potential_page_fault(s);
@ -2646,7 +2590,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op,
break; break;
case 0x11: /* STPX D2(B2) [S] */ case 0x11: /* STPX D2(B2) [S] */
/* Store Prefix */ /* Store Prefix */
check_privileged(env, s, ilc); check_privileged(s);
decode_rs(s, insn, &r1, &r3, &b2, &d2); decode_rs(s, insn, &r1, &r3, &b2, &d2);
tmp = get_address(s, 0, b2, d2); tmp = get_address(s, 0, b2, d2);
tmp2 = tcg_temp_new_i64(); tmp2 = tcg_temp_new_i64();
@ -2657,7 +2601,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op,
break; break;
case 0x12: /* STAP D2(B2) [S] */ case 0x12: /* STAP D2(B2) [S] */
/* Store CPU Address */ /* Store CPU Address */
check_privileged(env, s, ilc); check_privileged(s);
decode_rs(s, insn, &r1, &r3, &b2, &d2); decode_rs(s, insn, &r1, &r3, &b2, &d2);
tmp = get_address(s, 0, b2, d2); tmp = get_address(s, 0, b2, d2);
tmp2 = tcg_temp_new_i64(); tmp2 = tcg_temp_new_i64();
@ -2671,7 +2615,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op,
break; break;
case 0x21: /* IPTE R1,R2 [RRE] */ case 0x21: /* IPTE R1,R2 [RRE] */
/* Invalidate PTE */ /* Invalidate PTE */
check_privileged(env, s, ilc); check_privileged(s);
r1 = (insn >> 4) & 0xf; r1 = (insn >> 4) & 0xf;
r2 = insn & 0xf; r2 = insn & 0xf;
tmp = load_reg(r1); tmp = load_reg(r1);
@ -2682,7 +2626,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op,
break; break;
case 0x29: /* ISKE R1,R2 [RRE] */ case 0x29: /* ISKE R1,R2 [RRE] */
/* Insert Storage Key Extended */ /* Insert Storage Key Extended */
check_privileged(env, s, ilc); check_privileged(s);
r1 = (insn >> 4) & 0xf; r1 = (insn >> 4) & 0xf;
r2 = insn & 0xf; r2 = insn & 0xf;
tmp = load_reg(r2); tmp = load_reg(r2);
@ -2694,7 +2638,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op,
break; break;
case 0x2a: /* RRBE R1,R2 [RRE] */ case 0x2a: /* RRBE R1,R2 [RRE] */
/* Set Storage Key Extended */ /* Set Storage Key Extended */
check_privileged(env, s, ilc); check_privileged(s);
r1 = (insn >> 4) & 0xf; r1 = (insn >> 4) & 0xf;
r2 = insn & 0xf; r2 = insn & 0xf;
tmp32_1 = load_reg32(r1); tmp32_1 = load_reg32(r1);
@ -2706,7 +2650,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op,
break; break;
case 0x2b: /* SSKE R1,R2 [RRE] */ case 0x2b: /* SSKE R1,R2 [RRE] */
/* Set Storage Key Extended */ /* Set Storage Key Extended */
check_privileged(env, s, ilc); check_privileged(s);
r1 = (insn >> 4) & 0xf; r1 = (insn >> 4) & 0xf;
r2 = insn & 0xf; r2 = insn & 0xf;
tmp32_1 = load_reg32(r1); tmp32_1 = load_reg32(r1);
@ -2717,12 +2661,12 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op,
break; break;
case 0x34: /* STCH ? */ case 0x34: /* STCH ? */
/* Store Subchannel */ /* Store Subchannel */
check_privileged(env, s, ilc); check_privileged(s);
gen_op_movi_cc(s, 3); gen_op_movi_cc(s, 3);
break; break;
case 0x46: /* STURA R1,R2 [RRE] */ case 0x46: /* STURA R1,R2 [RRE] */
/* Store Using Real Address */ /* Store Using Real Address */
check_privileged(env, s, ilc); check_privileged(s);
r1 = (insn >> 4) & 0xf; r1 = (insn >> 4) & 0xf;
r2 = insn & 0xf; r2 = insn & 0xf;
tmp32_1 = load_reg32(r1); tmp32_1 = load_reg32(r1);
@ -2734,7 +2678,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op,
break; break;
case 0x50: /* CSP R1,R2 [RRE] */ case 0x50: /* CSP R1,R2 [RRE] */
/* Compare And Swap And Purge */ /* Compare And Swap And Purge */
check_privileged(env, s, ilc); check_privileged(s);
r1 = (insn >> 4) & 0xf; r1 = (insn >> 4) & 0xf;
r2 = insn & 0xf; r2 = insn & 0xf;
tmp32_1 = tcg_const_i32(r1); tmp32_1 = tcg_const_i32(r1);
@ -2746,7 +2690,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op,
break; break;
case 0x5f: /* CHSC ? */ case 0x5f: /* CHSC ? */
/* Channel Subsystem Call */ /* Channel Subsystem Call */
check_privileged(env, s, ilc); check_privileged(s);
gen_op_movi_cc(s, 3); gen_op_movi_cc(s, 3);
break; break;
case 0x78: /* STCKE D2(B2) [S] */ case 0x78: /* STCKE D2(B2) [S] */
@ -2760,19 +2704,19 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op,
break; break;
case 0x79: /* SACF D2(B2) [S] */ case 0x79: /* SACF D2(B2) [S] */
/* Set Address Space Control Fast */ /* Set Address Space Control Fast */
check_privileged(env, s, ilc); check_privileged(s);
decode_rs(s, insn, &r1, &r3, &b2, &d2); decode_rs(s, insn, &r1, &r3, &b2, &d2);
tmp = get_address(s, 0, b2, d2); tmp = get_address(s, 0, b2, d2);
potential_page_fault(s); potential_page_fault(s);
gen_helper_sacf(cpu_env, tmp); gen_helper_sacf(cpu_env, tmp);
tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp);
/* addressing mode has changed, so end the block */ /* addressing mode has changed, so end the block */
s->pc += ilc * 2; s->pc = s->next_pc;
update_psw_addr(s); update_psw_addr(s);
s->is_jmp = DISAS_JUMP; s->is_jmp = DISAS_JUMP;
break; break;
case 0x7d: /* STSI D2,(B2) [S] */ case 0x7d: /* STSI D2,(B2) [S] */
check_privileged(env, s, ilc); check_privileged(s);
decode_rs(s, insn, &r1, &r3, &b2, &d2); decode_rs(s, insn, &r1, &r3, &b2, &d2);
tmp = get_address(s, 0, b2, d2); tmp = get_address(s, 0, b2, d2);
tmp32_1 = load_reg32(0); tmp32_1 = load_reg32(0);
@ -2798,7 +2742,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op,
break; break;
case 0xb1: /* STFL D2(B2) [S] */ case 0xb1: /* STFL D2(B2) [S] */
/* Store Facility List (CPU features) at 200 */ /* Store Facility List (CPU features) at 200 */
check_privileged(env, s, ilc); check_privileged(s);
tmp2 = tcg_const_i64(0xc0000000); tmp2 = tcg_const_i64(0xc0000000);
tmp = tcg_const_i64(200); tmp = tcg_const_i64(200);
tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s)); 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; break;
case 0xb2: /* LPSWE D2(B2) [S] */ case 0xb2: /* LPSWE D2(B2) [S] */
/* Load PSW Extended */ /* Load PSW Extended */
check_privileged(env, s, ilc); check_privileged(s);
decode_rs(s, insn, &r1, &r3, &b2, &d2); decode_rs(s, insn, &r1, &r3, &b2, &d2);
tmp = get_address(s, 0, b2, d2); tmp = get_address(s, 0, b2, d2);
tmp2 = tcg_temp_new_i64(); tmp2 = tcg_temp_new_i64();
@ -2824,7 +2768,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op,
break; break;
case 0x20: /* SERVC R1,R2 [RRE] */ case 0x20: /* SERVC R1,R2 [RRE] */
/* SCLP Service call (PV hypercall) */ /* SCLP Service call (PV hypercall) */
check_privileged(env, s, ilc); check_privileged(s);
potential_page_fault(s); potential_page_fault(s);
tmp32_1 = load_reg32(r2); tmp32_1 = load_reg32(r2);
tmp = load_reg(r1); tmp = load_reg(r1);
@ -2836,7 +2780,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op,
#endif #endif
default: default:
LOG_DISAS("illegal b2 operation 0x%x\n", op); LOG_DISAS("illegal b2 operation 0x%x\n", op);
gen_illegal_opcode(env, s, ilc); gen_illegal_opcode(s);
break; break;
} }
} }
@ -3112,7 +3056,7 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3,
break; break;
default: default:
LOG_DISAS("illegal b3 operation 0x%x\n", op); LOG_DISAS("illegal b3 operation 0x%x\n", op);
gen_illegal_opcode(env, s, 2); gen_illegal_opcode(s);
break; break;
} }
@ -3419,7 +3363,7 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1,
break; break;
default: default:
LOG_DISAS("illegal b9 operation 0x%x\n", op); LOG_DISAS("illegal b9 operation 0x%x\n", op);
gen_illegal_opcode(env, s, 2); gen_illegal_opcode(s);
break; break;
} }
} }
@ -3525,7 +3469,7 @@ static void disas_c0(CPUS390XState *env, DisasContext *s, int op, int r1, int i2
break; break;
default: default:
LOG_DISAS("illegal c0 operation 0x%x\n", op); LOG_DISAS("illegal c0 operation 0x%x\n", op);
gen_illegal_opcode(env, s, 3); gen_illegal_opcode(s);
break; break;
} }
} }
@ -3559,7 +3503,7 @@ static void disas_c2(CPUS390XState *env, DisasContext *s, int op, int r1,
break; break;
default: default:
LOG_DISAS("illegal c2 operation 0x%x\n", op); LOG_DISAS("illegal c2 operation 0x%x\n", op);
gen_illegal_opcode(env, s, 3); gen_illegal_opcode(s);
break; break;
} }
} }
@ -3589,14 +3533,11 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s)
uint64_t insn; uint64_t insn;
int op, r1, r2, r3, d1, d2, x2, b1, b2, i, i2, r1b; int op, r1, r2, r3, d1, d2, x2, b1, b2, i, i2, r1b;
TCGv_i32 vl; TCGv_i32 vl;
int ilc;
int l1; int l1;
opc = cpu_ldub_code(env, s->pc); opc = cpu_ldub_code(env, s->pc);
LOG_DISAS("opc 0x%x\n", opc); LOG_DISAS("opc 0x%x\n", opc);
ilc = get_ilc(opc);
switch (opc) { switch (opc) {
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
case 0x01: /* SAM */ case 0x01: /* SAM */
@ -3649,15 +3590,13 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s)
update_psw_addr(s); update_psw_addr(s);
gen_op_calc_cc(s); gen_op_calc_cc(s);
tmp32_1 = tcg_const_i32(i); tmp32_1 = tcg_const_i32(i);
tmp32_2 = tcg_const_i32(ilc * 2); tmp32_2 = tcg_const_i32(s->next_pc - s->pc);
tmp32_3 = tcg_const_i32(EXCP_SVC);
tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, int_svc_code)); 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)); tcg_gen_st_i32(tmp32_2, cpu_env, offsetof(CPUS390XState, int_svc_ilen));
gen_helper_exception(cpu_env, tmp32_3); gen_exception(EXCP_SVC);
s->is_jmp = DISAS_EXCP; s->is_jmp = DISAS_EXCP;
tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i32(tmp32_2); tcg_temp_free_i32(tmp32_2);
tcg_temp_free_i32(tmp32_3);
break; break;
case 0xd: /* BASR R1,R2 [RR] */ case 0xd: /* BASR R1,R2 [RR] */
insn = ld_code2(env, s->pc); insn = ld_code2(env, s->pc);
@ -4148,7 +4087,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s)
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
case 0x80: /* SSM D2(B2) [S] */ case 0x80: /* SSM D2(B2) [S] */
/* Set System Mask */ /* Set System Mask */
check_privileged(env, s, ilc); check_privileged(s);
insn = ld_code4(env, s->pc); insn = ld_code4(env, s->pc);
decode_rs(s, insn, &r1, &r3, &b2, &d2); decode_rs(s, insn, &r1, &r3, &b2, &d2);
tmp = get_address(s, 0, b2, d2); tmp = get_address(s, 0, b2, d2);
@ -4164,7 +4103,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s)
break; break;
case 0x82: /* LPSW D2(B2) [S] */ case 0x82: /* LPSW D2(B2) [S] */
/* Load PSW */ /* Load PSW */
check_privileged(env, s, ilc); check_privileged(s);
insn = ld_code4(env, s->pc); insn = ld_code4(env, s->pc);
decode_rs(s, insn, &r1, &r3, &b2, &d2); decode_rs(s, insn, &r1, &r3, &b2, &d2);
tmp = get_address(s, 0, b2, d2); tmp = get_address(s, 0, b2, d2);
@ -4184,7 +4123,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s)
break; break;
case 0x83: /* DIAG R1,R3,D2 [RS] */ case 0x83: /* DIAG R1,R3,D2 [RS] */
/* Diagnose call (KVM hypercall) */ /* Diagnose call (KVM hypercall) */
check_privileged(env, s, ilc); check_privileged(s);
potential_page_fault(s); potential_page_fault(s);
insn = ld_code4(env, s->pc); insn = ld_code4(env, s->pc);
decode_rs(s, insn, &r1, &r3, &b2, &d2); 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 #ifndef CONFIG_USER_ONLY
case 0xac: /* STNSM D1(B1),I2 [SI] */ case 0xac: /* STNSM D1(B1),I2 [SI] */
case 0xad: /* STOSM 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); insn = ld_code4(env, s->pc);
tmp = decode_si(s, insn, &i2, &b1, &d1); tmp = decode_si(s, insn, &i2, &b1, &d1);
tmp2 = tcg_temp_new_i64(); tmp2 = tcg_temp_new_i64();
@ -4418,7 +4357,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s)
tcg_temp_free_i64(tmp2); tcg_temp_free_i64(tmp2);
break; break;
case 0xae: /* SIGP R1,R3,D2(B2) [RS] */ case 0xae: /* SIGP R1,R3,D2(B2) [RS] */
check_privileged(env, s, ilc); check_privileged(s);
insn = ld_code4(env, s->pc); insn = ld_code4(env, s->pc);
decode_rs(s, insn, &r1, &r3, &b2, &d2); decode_rs(s, insn, &r1, &r3, &b2, &d2);
tmp = get_address(s, 0, 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); tcg_temp_free_i32(tmp32_1);
break; break;
case 0xb1: /* LRA R1,D2(X2, B2) [RX] */ case 0xb1: /* LRA R1,D2(X2, B2) [RX] */
check_privileged(env, s, ilc); check_privileged(s);
insn = ld_code4(env, s->pc); insn = ld_code4(env, s->pc);
tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2);
tmp32_1 = tcg_const_i32(r1); tmp32_1 = tcg_const_i32(r1);
@ -4476,7 +4415,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s)
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
case 0xb6: /* STCTL R1,R3,D2(B2) [RS] */ case 0xb6: /* STCTL R1,R3,D2(B2) [RS] */
/* Store Control */ /* Store Control */
check_privileged(env, s, ilc); check_privileged(s);
insn = ld_code4(env, s->pc); insn = ld_code4(env, s->pc);
decode_rs(s, insn, &r1, &r3, &b2, &d2); decode_rs(s, insn, &r1, &r3, &b2, &d2);
tmp = get_address(s, 0, b2, d2); tmp = get_address(s, 0, b2, d2);
@ -4490,7 +4429,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s)
break; break;
case 0xb7: /* LCTL R1,R3,D2(B2) [RS] */ case 0xb7: /* LCTL R1,R3,D2(B2) [RS] */
/* Load Control */ /* Load Control */
check_privileged(env, s, ilc); check_privileged(s);
insn = ld_code4(env, s->pc); insn = ld_code4(env, s->pc);
decode_rs(s, insn, &r1, &r3, &b2, &d2); decode_rs(s, insn, &r1, &r3, &b2, &d2);
tmp = get_address(s, 0, 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 #ifndef CONFIG_USER_ONLY
case 0xda: /* MVCP D1(R1,B1),D2(B2),R3 [SS] */ case 0xda: /* MVCP D1(R1,B1),D2(B2),R3 [SS] */
case 0xdb: /* MVCS 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); potential_page_fault(s);
insn = ld_code6(env, s->pc); insn = ld_code6(env, s->pc);
r1 = (insn >> 36) & 0xf; r1 = (insn >> 36) & 0xf;
@ -4712,7 +4651,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s)
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
case 0xe5: case 0xe5:
/* Test Protection */ /* Test Protection */
check_privileged(env, s, ilc); check_privileged(s);
insn = ld_code6(env, s->pc); insn = ld_code6(env, s->pc);
debug_insn(insn); debug_insn(insn);
disas_e5(env, s, insn); disas_e5(env, s, insn);
@ -4742,7 +4681,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s)
break; break;
default: default:
qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%x\n", opc); qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%x\n", opc);
gen_illegal_opcode(env, s, ilc); gen_illegal_opcode(s);
break; break;
} }
} }
@ -5273,19 +5212,22 @@ static const DisasInsn *extract_insn(CPUS390XState *env, DisasContext *s,
DisasFields *f) DisasFields *f)
{ {
uint64_t insn, pc = s->pc; uint64_t insn, pc = s->pc;
int op, op2; int op, op2, ilen;
const DisasInsn *info; const DisasInsn *info;
insn = ld_code2(env, pc); insn = ld_code2(env, pc);
op = (insn >> 8) & 0xff; op = (insn >> 8) & 0xff;
switch (get_ilc(op)) { ilen = get_ilen(op);
case 1: s->next_pc = s->pc + ilen;
switch (ilen) {
case 2:
insn = insn << 48; insn = insn << 48;
break; break;
case 2: case 4:
insn = ld_code4(env, pc) << 32; insn = ld_code4(env, pc) << 32;
break; break;
case 3: case 6:
insn = (insn << 48) | (ld_code4(env, pc + 2) << 16); insn = (insn << 48) | (ld_code4(env, pc + 2) << 16);
break; break;
default: default:
@ -5361,9 +5303,6 @@ static ExitStatus translate_one(CPUS390XState *env, DisasContext *s)
insn = extract_insn(env, s, &f); 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 not found, try the old interpreter. This includes ILLOPC. */
if (insn == NULL) { if (insn == NULL) {
disas_s390_insn(env, s); disas_s390_insn(env, s);
@ -5452,6 +5391,7 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env,
int num_insns, max_insns; int num_insns, max_insns;
CPUBreakpoint *bp; CPUBreakpoint *bp;
ExitStatus status; ExitStatus status;
bool do_debug;
pc_start = tb->pc; pc_start = tb->pc;
@ -5463,7 +5403,7 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env,
dc.tb = tb; dc.tb = tb;
dc.pc = pc_start; dc.pc = pc_start;
dc.cc_op = CC_OP_DYNAMIC; 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; dc.is_jmp = DISAS_NEXT;
gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; 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(); gen_icount_start();
do { 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) { if (search_pc) {
j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
if (lj < j) { if (lj < j) {
@ -5508,7 +5440,19 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env,
tcg_gen_debug_insn_start(dc.pc); 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, /* If we reach a page boundary, are single stepping,
or exhaust instruction count, stop generation. */ 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 */ so make sure the cc op type is in env */
gen_op_set_cc_op(&dc); gen_op_set_cc_op(&dc);
} }
if (env->singlestep_enabled) { if (do_debug) {
gen_debug(&dc); gen_exception(EXCP_DEBUG);
} else { } else {
/* Generate the return instruction */ /* Generate the return instruction */
tcg_gen_exit_tb(0); tcg_gen_exit_tb(0);