target-s390x: PER successful-branching event support
For the PER successful-branching event support, we can't rely on any QEMU infrastucture. We therefore call an helper in all places where a branch can be taken. We have to pay attention to the branch to next case, as it's still a taken branch. We don't need to care about the cases using goto_tb, as we have disabled them in the previous patch. Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
		
							parent
							
								
									777c98c32c
								
							
						
					
					
						commit
						2c2275eb41
					
				@ -117,6 +117,7 @@ DEF_HELPER_FLAGS_2(lurag, TCG_CALL_NO_WG, i64, env, i64)
 | 
				
			|||||||
DEF_HELPER_FLAGS_3(stura, TCG_CALL_NO_WG, void, env, i64, i64)
 | 
					DEF_HELPER_FLAGS_3(stura, TCG_CALL_NO_WG, void, env, i64, i64)
 | 
				
			||||||
DEF_HELPER_FLAGS_3(sturg, TCG_CALL_NO_WG, void, env, i64, i64)
 | 
					DEF_HELPER_FLAGS_3(sturg, TCG_CALL_NO_WG, void, env, i64, i64)
 | 
				
			||||||
DEF_HELPER_1(per_check_exception, void, env)
 | 
					DEF_HELPER_1(per_check_exception, void, env)
 | 
				
			||||||
 | 
					DEF_HELPER_FLAGS_3(per_branch, TCG_CALL_NO_RWG, void, env, i64, i64)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEF_HELPER_2(xsch, void, env, i64)
 | 
					DEF_HELPER_2(xsch, void, env, i64)
 | 
				
			||||||
DEF_HELPER_2(csch, void, env, i64)
 | 
					DEF_HELPER_2(csch, void, env, i64)
 | 
				
			||||||
 | 
				
			|||||||
@ -608,4 +608,15 @@ void HELPER(per_check_exception)(CPUS390XState *env)
 | 
				
			|||||||
        cpu_loop_exit(cs);
 | 
					        cpu_loop_exit(cs);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void HELPER(per_branch)(CPUS390XState *env, uint64_t from, uint64_t to)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if ((env->cregs[9] & PER_CR9_EVENT_BRANCH)) {
 | 
				
			||||||
 | 
					        if (!(env->cregs[9] & PER_CR9_CONTROL_BRANCH_ADDRESS)
 | 
				
			||||||
 | 
					            || get_per_in_range(env, to)) {
 | 
				
			||||||
 | 
					            env->per_address = from;
 | 
				
			||||||
 | 
					            env->per_perc_atmid = PER_CODE_EVENT_BRANCH | get_per_atmid(env);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
@ -249,6 +249,38 @@ static void update_psw_addr(DisasContext *s)
 | 
				
			|||||||
    tcg_gen_movi_i64(psw_addr, s->pc);
 | 
					    tcg_gen_movi_i64(psw_addr, s->pc);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void per_branch(DisasContext *s, bool to_next)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#ifndef CONFIG_USER_ONLY
 | 
				
			||||||
 | 
					    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);
 | 
				
			||||||
 | 
					        if (to_next) {
 | 
				
			||||||
 | 
					            tcg_temp_free_i64(next_pc);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        tcg_temp_free_i64(pc);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void per_branch_cond(DisasContext *s, TCGCond cond,
 | 
				
			||||||
 | 
					                            TCGv_i64 arg1, TCGv_i64 arg2)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#ifndef CONFIG_USER_ONLY
 | 
				
			||||||
 | 
					    if (s->tb->flags & FLAG_MASK_PER) {
 | 
				
			||||||
 | 
					        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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        gen_set_label(lab);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void update_cc_op(DisasContext *s)
 | 
					static void update_cc_op(DisasContext *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (s->cc_op != CC_OP_DYNAMIC && s->cc_op != CC_OP_STATIC) {
 | 
					    if (s->cc_op != CC_OP_DYNAMIC && s->cc_op != CC_OP_STATIC) {
 | 
				
			||||||
@ -1183,6 +1215,7 @@ static void help_l2_shift(DisasContext *s, DisasFields *f,
 | 
				
			|||||||
static ExitStatus help_goto_direct(DisasContext *s, uint64_t dest)
 | 
					static ExitStatus help_goto_direct(DisasContext *s, uint64_t dest)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (dest == s->next_pc) {
 | 
					    if (dest == s->next_pc) {
 | 
				
			||||||
 | 
					        per_branch(s, true);
 | 
				
			||||||
        return NO_EXIT;
 | 
					        return NO_EXIT;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (use_goto_tb(s, dest)) {
 | 
					    if (use_goto_tb(s, dest)) {
 | 
				
			||||||
@ -1193,6 +1226,7 @@ static ExitStatus help_goto_direct(DisasContext *s, uint64_t dest)
 | 
				
			|||||||
        return EXIT_GOTO_TB;
 | 
					        return EXIT_GOTO_TB;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        tcg_gen_movi_i64(psw_addr, dest);
 | 
					        tcg_gen_movi_i64(psw_addr, dest);
 | 
				
			||||||
 | 
					        per_branch(s, false);
 | 
				
			||||||
        return EXIT_PC_UPDATED;
 | 
					        return EXIT_PC_UPDATED;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -1212,6 +1246,7 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c,
 | 
				
			|||||||
    if (is_imm) {
 | 
					    if (is_imm) {
 | 
				
			||||||
        if (dest == s->next_pc) {
 | 
					        if (dest == s->next_pc) {
 | 
				
			||||||
            /* Branch to next.  */
 | 
					            /* Branch to next.  */
 | 
				
			||||||
 | 
					            per_branch(s, true);
 | 
				
			||||||
            ret = NO_EXIT;
 | 
					            ret = NO_EXIT;
 | 
				
			||||||
            goto egress;
 | 
					            goto egress;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -1227,6 +1262,7 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c,
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        if (c->cond == TCG_COND_ALWAYS) {
 | 
					        if (c->cond == TCG_COND_ALWAYS) {
 | 
				
			||||||
            tcg_gen_mov_i64(psw_addr, cdest);
 | 
					            tcg_gen_mov_i64(psw_addr, cdest);
 | 
				
			||||||
 | 
					            per_branch(s, false);
 | 
				
			||||||
            ret = EXIT_PC_UPDATED;
 | 
					            ret = EXIT_PC_UPDATED;
 | 
				
			||||||
            goto egress;
 | 
					            goto egress;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -1297,6 +1333,7 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c,
 | 
				
			|||||||
        if (c->is_64) {
 | 
					        if (c->is_64) {
 | 
				
			||||||
            tcg_gen_movcond_i64(c->cond, psw_addr, c->u.s64.a, c->u.s64.b,
 | 
					            tcg_gen_movcond_i64(c->cond, psw_addr, c->u.s64.a, c->u.s64.b,
 | 
				
			||||||
                                cdest, next);
 | 
					                                cdest, next);
 | 
				
			||||||
 | 
					            per_branch_cond(s, c->cond, c->u.s64.a, c->u.s64.b);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            TCGv_i32 t0 = tcg_temp_new_i32();
 | 
					            TCGv_i32 t0 = tcg_temp_new_i32();
 | 
				
			||||||
            TCGv_i64 t1 = tcg_temp_new_i64();
 | 
					            TCGv_i64 t1 = tcg_temp_new_i64();
 | 
				
			||||||
@ -1305,6 +1342,7 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c,
 | 
				
			|||||||
            tcg_gen_extu_i32_i64(t1, t0);
 | 
					            tcg_gen_extu_i32_i64(t1, t0);
 | 
				
			||||||
            tcg_temp_free_i32(t0);
 | 
					            tcg_temp_free_i32(t0);
 | 
				
			||||||
            tcg_gen_movcond_i64(TCG_COND_NE, psw_addr, t1, z, cdest, next);
 | 
					            tcg_gen_movcond_i64(TCG_COND_NE, psw_addr, t1, z, cdest, next);
 | 
				
			||||||
 | 
					            per_branch_cond(s, TCG_COND_NE, t1, z);
 | 
				
			||||||
            tcg_temp_free_i64(t1);
 | 
					            tcg_temp_free_i64(t1);
 | 
				
			||||||
            tcg_temp_free_i64(z);
 | 
					            tcg_temp_free_i64(z);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -1437,6 +1475,7 @@ static ExitStatus op_bas(DisasContext *s, DisasOps *o)
 | 
				
			|||||||
    tcg_gen_movi_i64(o->out, pc_to_link_info(s, s->next_pc));
 | 
					    tcg_gen_movi_i64(o->out, pc_to_link_info(s, s->next_pc));
 | 
				
			||||||
    if (!TCGV_IS_UNUSED_I64(o->in2)) {
 | 
					    if (!TCGV_IS_UNUSED_I64(o->in2)) {
 | 
				
			||||||
        tcg_gen_mov_i64(psw_addr, o->in2);
 | 
					        tcg_gen_mov_i64(psw_addr, o->in2);
 | 
				
			||||||
 | 
					        per_branch(s, false);
 | 
				
			||||||
        return EXIT_PC_UPDATED;
 | 
					        return EXIT_PC_UPDATED;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        return NO_EXIT;
 | 
					        return NO_EXIT;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user