mirror of
https://github.com/qemu/qemu.git
synced 2024-11-26 12:23:36 +08:00
target-s390x: PER: add Breaking-Event-Address register
This patch adds support for PER Breaking-Event-Address register. Like real hardware, it save the current PSW address when the PSW address is changed by an instruction. We have to take care of optimizations QEMU does, a branch to the next instruction is still a branch. This register is copied to low core memory when a program exception happens. Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
parent
83bb161299
commit
3da0ab3529
@ -117,6 +117,9 @@ static void s390_cpu_initial_reset(CPUState *s)
|
||||
env->cregs[0] = CR0_RESET;
|
||||
env->cregs[14] = CR14_RESET;
|
||||
|
||||
/* architectured initial value for Breaking-Event-Address register */
|
||||
env->gbea = 1;
|
||||
|
||||
env->pfault_token = -1UL;
|
||||
env->ext_index = -1;
|
||||
for (i = 0; i < ARRAY_SIZE(env->io_index); i++) {
|
||||
@ -152,6 +155,9 @@ static void s390_cpu_full_reset(CPUState *s)
|
||||
env->cregs[0] = CR0_RESET;
|
||||
env->cregs[14] = CR14_RESET;
|
||||
|
||||
/* architectured initial value for Breaking-Event-Address register */
|
||||
env->gbea = 1;
|
||||
|
||||
env->pfault_token = -1UL;
|
||||
env->ext_index = -1;
|
||||
for (i = 0; i < ARRAY_SIZE(env->io_index); i++) {
|
||||
|
@ -789,14 +789,16 @@ typedef struct LowCore
|
||||
uint8_t pad5[0xf4-0xf0]; /* 0x0f0 */
|
||||
uint32_t external_damage_code; /* 0x0f4 */
|
||||
uint64_t failing_storage_address; /* 0x0f8 */
|
||||
uint8_t pad6[0x120-0x100]; /* 0x100 */
|
||||
uint8_t pad6[0x110-0x100]; /* 0x100 */
|
||||
uint64_t per_breaking_event_addr; /* 0x110 */
|
||||
uint8_t pad7[0x120-0x118]; /* 0x118 */
|
||||
PSW restart_old_psw; /* 0x120 */
|
||||
PSW external_old_psw; /* 0x130 */
|
||||
PSW svc_old_psw; /* 0x140 */
|
||||
PSW program_old_psw; /* 0x150 */
|
||||
PSW mcck_old_psw; /* 0x160 */
|
||||
PSW io_old_psw; /* 0x170 */
|
||||
uint8_t pad7[0x1a0-0x180]; /* 0x180 */
|
||||
uint8_t pad8[0x1a0-0x180]; /* 0x180 */
|
||||
PSW restart_new_psw; /* 0x1a0 */
|
||||
PSW external_new_psw; /* 0x1b0 */
|
||||
PSW svc_new_psw; /* 0x1c0 */
|
||||
@ -814,10 +816,10 @@ typedef struct LowCore
|
||||
uint64_t last_update_clock; /* 0x280 */
|
||||
uint64_t steal_clock; /* 0x288 */
|
||||
PSW return_mcck_psw; /* 0x290 */
|
||||
uint8_t pad8[0xc00-0x2a0]; /* 0x2a0 */
|
||||
uint8_t pad9[0xc00-0x2a0]; /* 0x2a0 */
|
||||
/* System info area */
|
||||
uint64_t save_area[16]; /* 0xc00 */
|
||||
uint8_t pad9[0xd40-0xc80]; /* 0xc80 */
|
||||
uint8_t pad10[0xd40-0xc80]; /* 0xc80 */
|
||||
uint64_t kernel_stack; /* 0xd40 */
|
||||
uint64_t thread_info; /* 0xd48 */
|
||||
uint64_t async_stack; /* 0xd50 */
|
||||
@ -825,7 +827,7 @@ typedef struct LowCore
|
||||
uint64_t user_asce; /* 0xd60 */
|
||||
uint64_t panic_stack; /* 0xd68 */
|
||||
uint64_t user_exec_asce; /* 0xd70 */
|
||||
uint8_t pad10[0xdc0-0xd78]; /* 0xd78 */
|
||||
uint8_t pad11[0xdc0-0xd78]; /* 0xd78 */
|
||||
|
||||
/* SMP info area: defined by DJB */
|
||||
uint64_t clock_comparator; /* 0xdc0 */
|
||||
|
@ -293,6 +293,7 @@ static void do_program_interrupt(CPUS390XState *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);
|
||||
|
||||
|
@ -150,6 +150,7 @@ void s390_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
|
||||
|
||||
static TCGv_i64 psw_addr;
|
||||
static TCGv_i64 psw_mask;
|
||||
static TCGv_i64 gbea;
|
||||
|
||||
static TCGv_i32 cc_op;
|
||||
static TCGv_i64 cc_src;
|
||||
@ -173,6 +174,9 @@ void s390x_translate_init(void)
|
||||
psw_mask = tcg_global_mem_new_i64(TCG_AREG0,
|
||||
offsetof(CPUS390XState, psw.mask),
|
||||
"psw_mask");
|
||||
gbea = tcg_global_mem_new_i64(TCG_AREG0,
|
||||
offsetof(CPUS390XState, gbea),
|
||||
"gbea");
|
||||
|
||||
cc_op = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUS390XState, cc_op),
|
||||
"cc_op");
|
||||
@ -252,14 +256,14 @@ static void update_psw_addr(DisasContext *s)
|
||||
static void per_branch(DisasContext *s, bool to_next)
|
||||
{
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
tcg_gen_movi_i64(gbea, s->pc);
|
||||
|
||||
if (s->tb->flags & FLAG_MASK_PER) {
|
||||
TCGv_i64 pc = tcg_const_i64(s->pc);
|
||||
TCGv_i64 next_pc = to_next ? tcg_const_i64(s->next_pc) : psw_addr;
|
||||
gen_helper_per_branch(cpu_env, pc, next_pc);
|
||||
gen_helper_per_branch(cpu_env, gbea, next_pc);
|
||||
if (to_next) {
|
||||
tcg_temp_free_i64(next_pc);
|
||||
}
|
||||
tcg_temp_free_i64(pc);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -272,15 +276,23 @@ static void per_branch_cond(DisasContext *s, TCGCond cond,
|
||||
TCGLabel *lab = gen_new_label();
|
||||
tcg_gen_brcond_i64(tcg_invert_cond(cond), arg1, arg2, lab);
|
||||
|
||||
TCGv_i64 pc = tcg_const_i64(s->pc);
|
||||
gen_helper_per_branch(cpu_env, pc, psw_addr);
|
||||
tcg_temp_free_i64(pc);
|
||||
tcg_gen_movi_i64(gbea, s->pc);
|
||||
gen_helper_per_branch(cpu_env, gbea, psw_addr);
|
||||
|
||||
gen_set_label(lab);
|
||||
} else {
|
||||
TCGv_i64 pc = tcg_const_i64(s->pc);
|
||||
tcg_gen_movcond_i64(cond, gbea, arg1, arg2, gbea, pc);
|
||||
tcg_temp_free_i64(pc);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void per_breaking_event(DisasContext *s)
|
||||
{
|
||||
tcg_gen_movi_i64(gbea, s->pc);
|
||||
}
|
||||
|
||||
static void update_cc_op(DisasContext *s)
|
||||
{
|
||||
if (s->cc_op != CC_OP_DYNAMIC && s->cc_op != CC_OP_STATIC) {
|
||||
@ -1220,6 +1232,7 @@ static ExitStatus help_goto_direct(DisasContext *s, uint64_t dest)
|
||||
}
|
||||
if (use_goto_tb(s, dest)) {
|
||||
update_cc_op(s);
|
||||
per_breaking_event(s);
|
||||
tcg_gen_goto_tb(0);
|
||||
tcg_gen_movi_i64(psw_addr, dest);
|
||||
tcg_gen_exit_tb((uintptr_t)s->tb);
|
||||
@ -1287,6 +1300,7 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c,
|
||||
|
||||
/* Branch taken. */
|
||||
gen_set_label(lab);
|
||||
per_breaking_event(s);
|
||||
tcg_gen_goto_tb(1);
|
||||
tcg_gen_movi_i64(psw_addr, dest);
|
||||
tcg_gen_exit_tb((uintptr_t)s->tb + 1);
|
||||
@ -1318,6 +1332,7 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c,
|
||||
if (is_imm) {
|
||||
tcg_gen_movi_i64(psw_addr, dest);
|
||||
}
|
||||
per_breaking_event(s);
|
||||
ret = EXIT_PC_UPDATED;
|
||||
}
|
||||
} else {
|
||||
@ -2550,6 +2565,7 @@ static ExitStatus op_lpsw(DisasContext *s, DisasOps *o)
|
||||
TCGv_i64 t1, t2;
|
||||
|
||||
check_privileged(s);
|
||||
per_breaking_event(s);
|
||||
|
||||
t1 = tcg_temp_new_i64();
|
||||
t2 = tcg_temp_new_i64();
|
||||
@ -2569,6 +2585,7 @@ static ExitStatus op_lpswe(DisasContext *s, DisasOps *o)
|
||||
TCGv_i64 t1, t2;
|
||||
|
||||
check_privileged(s);
|
||||
per_breaking_event(s);
|
||||
|
||||
t1 = tcg_temp_new_i64();
|
||||
t2 = tcg_temp_new_i64();
|
||||
|
Loading…
Reference in New Issue
Block a user