mirror of
https://github.com/qemu/qemu.git
synced 2024-12-01 07:43:35 +08:00
target/s390x: Fix EXECUTE of relative branches
Fix a problem similar to the one fixed by commit 703d03a4aa
("target/s390x: Fix EXECUTE of relative long instructions"), but now
for relative branches.
Reported-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20230426235813.198183-2-iii@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
This commit is contained in:
parent
c2485ea402
commit
e8ecdfeb30
@ -1534,18 +1534,51 @@ static DisasJumpType op_bal(DisasContext *s, DisasOps *o)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Disassemble the target of a branch. The results are returned in a form
|
||||
* suitable for passing into help_branch():
|
||||
*
|
||||
* - bool IS_IMM reflects whether the target is fixed or computed. Non-EXECUTEd
|
||||
* branches, whose DisasContext *S contains the relative immediate field RI,
|
||||
* are considered fixed. All the other branches are considered computed.
|
||||
* - int IMM is the value of RI.
|
||||
* - TCGv_i64 CDEST is the address of the computed target.
|
||||
*/
|
||||
#define disas_jdest(s, ri, is_imm, imm, cdest) do { \
|
||||
if (have_field(s, ri)) { \
|
||||
if (unlikely(s->ex_value)) { \
|
||||
cdest = tcg_temp_new_i64(); \
|
||||
tcg_gen_ld_i64(cdest, cpu_env, offsetof(CPUS390XState, ex_target));\
|
||||
tcg_gen_addi_i64(cdest, cdest, (int64_t)get_field(s, ri) * 2); \
|
||||
is_imm = false; \
|
||||
} else { \
|
||||
is_imm = true; \
|
||||
} \
|
||||
} else { \
|
||||
is_imm = false; \
|
||||
} \
|
||||
imm = is_imm ? get_field(s, ri) : 0; \
|
||||
} while (false)
|
||||
|
||||
static DisasJumpType op_basi(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
DisasCompare c;
|
||||
bool is_imm;
|
||||
int imm;
|
||||
|
||||
pc_to_link_info(o->out, s, s->pc_tmp);
|
||||
return help_goto_direct(s, s->base.pc_next + (int64_t)get_field(s, i2) * 2);
|
||||
|
||||
disas_jdest(s, i2, is_imm, imm, o->in2);
|
||||
disas_jcc(s, &c, 0xf);
|
||||
return help_branch(s, &c, is_imm, imm, o->in2);
|
||||
}
|
||||
|
||||
static DisasJumpType op_bc(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
int m1 = get_field(s, m1);
|
||||
bool is_imm = have_field(s, i2);
|
||||
int imm = is_imm ? get_field(s, i2) : 0;
|
||||
DisasCompare c;
|
||||
bool is_imm;
|
||||
int imm;
|
||||
|
||||
/* BCR with R2 = 0 causes no branching */
|
||||
if (have_field(s, r2) && get_field(s, r2) == 0) {
|
||||
@ -1562,6 +1595,7 @@ static DisasJumpType op_bc(DisasContext *s, DisasOps *o)
|
||||
return DISAS_NEXT;
|
||||
}
|
||||
|
||||
disas_jdest(s, i2, is_imm, imm, o->in2);
|
||||
disas_jcc(s, &c, m1);
|
||||
return help_branch(s, &c, is_imm, imm, o->in2);
|
||||
}
|
||||
@ -1569,10 +1603,10 @@ static DisasJumpType op_bc(DisasContext *s, DisasOps *o)
|
||||
static DisasJumpType op_bct32(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
int r1 = get_field(s, r1);
|
||||
bool is_imm = have_field(s, i2);
|
||||
int imm = is_imm ? get_field(s, i2) : 0;
|
||||
DisasCompare c;
|
||||
bool is_imm;
|
||||
TCGv_i64 t;
|
||||
int imm;
|
||||
|
||||
c.cond = TCG_COND_NE;
|
||||
c.is_64 = false;
|
||||
@ -1584,6 +1618,7 @@ static DisasJumpType op_bct32(DisasContext *s, DisasOps *o)
|
||||
c.u.s32.b = tcg_constant_i32(0);
|
||||
tcg_gen_extrl_i64_i32(c.u.s32.a, t);
|
||||
|
||||
disas_jdest(s, i2, is_imm, imm, o->in2);
|
||||
return help_branch(s, &c, is_imm, imm, o->in2);
|
||||
}
|
||||
|
||||
@ -1611,9 +1646,9 @@ static DisasJumpType op_bcth(DisasContext *s, DisasOps *o)
|
||||
static DisasJumpType op_bct64(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
int r1 = get_field(s, r1);
|
||||
bool is_imm = have_field(s, i2);
|
||||
int imm = is_imm ? get_field(s, i2) : 0;
|
||||
DisasCompare c;
|
||||
bool is_imm;
|
||||
int imm;
|
||||
|
||||
c.cond = TCG_COND_NE;
|
||||
c.is_64 = true;
|
||||
@ -1622,6 +1657,7 @@ static DisasJumpType op_bct64(DisasContext *s, DisasOps *o)
|
||||
c.u.s64.a = regs[r1];
|
||||
c.u.s64.b = tcg_constant_i64(0);
|
||||
|
||||
disas_jdest(s, i2, is_imm, imm, o->in2);
|
||||
return help_branch(s, &c, is_imm, imm, o->in2);
|
||||
}
|
||||
|
||||
@ -1629,10 +1665,10 @@ static DisasJumpType op_bx32(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
int r1 = get_field(s, r1);
|
||||
int r3 = get_field(s, r3);
|
||||
bool is_imm = have_field(s, i2);
|
||||
int imm = is_imm ? get_field(s, i2) : 0;
|
||||
DisasCompare c;
|
||||
bool is_imm;
|
||||
TCGv_i64 t;
|
||||
int imm;
|
||||
|
||||
c.cond = (s->insn->data ? TCG_COND_LE : TCG_COND_GT);
|
||||
c.is_64 = false;
|
||||
@ -1645,6 +1681,7 @@ static DisasJumpType op_bx32(DisasContext *s, DisasOps *o)
|
||||
tcg_gen_extrl_i64_i32(c.u.s32.b, regs[r3 | 1]);
|
||||
store_reg32_i64(r1, t);
|
||||
|
||||
disas_jdest(s, i2, is_imm, imm, o->in2);
|
||||
return help_branch(s, &c, is_imm, imm, o->in2);
|
||||
}
|
||||
|
||||
@ -1652,9 +1689,9 @@ static DisasJumpType op_bx64(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
int r1 = get_field(s, r1);
|
||||
int r3 = get_field(s, r3);
|
||||
bool is_imm = have_field(s, i2);
|
||||
int imm = is_imm ? get_field(s, i2) : 0;
|
||||
DisasCompare c;
|
||||
bool is_imm;
|
||||
int imm;
|
||||
|
||||
c.cond = (s->insn->data ? TCG_COND_LE : TCG_COND_GT);
|
||||
c.is_64 = true;
|
||||
@ -1668,6 +1705,7 @@ static DisasJumpType op_bx64(DisasContext *s, DisasOps *o)
|
||||
tcg_gen_add_i64(regs[r1], regs[r1], regs[r3]);
|
||||
c.u.s64.a = regs[r1];
|
||||
|
||||
disas_jdest(s, i2, is_imm, imm, o->in2);
|
||||
return help_branch(s, &c, is_imm, imm, o->in2);
|
||||
}
|
||||
|
||||
@ -1685,10 +1723,9 @@ static DisasJumpType op_cj(DisasContext *s, DisasOps *o)
|
||||
c.u.s64.a = o->in1;
|
||||
c.u.s64.b = o->in2;
|
||||
|
||||
is_imm = have_field(s, i4);
|
||||
if (is_imm) {
|
||||
imm = get_field(s, i4);
|
||||
} else {
|
||||
o->out = NULL;
|
||||
disas_jdest(s, i4, is_imm, imm, o->out);
|
||||
if (!is_imm && !o->out) {
|
||||
imm = 0;
|
||||
o->out = get_address(s, 0, get_field(s, b4),
|
||||
get_field(s, d4));
|
||||
@ -5764,15 +5801,13 @@ static void in2_a2(DisasContext *s, DisasOps *o)
|
||||
|
||||
static TCGv gen_ri2(DisasContext *s)
|
||||
{
|
||||
int64_t delta = (int64_t)get_field(s, i2) * 2;
|
||||
TCGv ri2;
|
||||
TCGv ri2 = NULL;
|
||||
bool is_imm;
|
||||
int imm;
|
||||
|
||||
if (unlikely(s->ex_value)) {
|
||||
ri2 = tcg_temp_new_i64();
|
||||
tcg_gen_ld_i64(ri2, cpu_env, offsetof(CPUS390XState, ex_target));
|
||||
tcg_gen_addi_i64(ri2, ri2, delta);
|
||||
} else {
|
||||
ri2 = tcg_constant_i64(s->base.pc_next + delta);
|
||||
disas_jdest(s, i2, is_imm, imm, ri2);
|
||||
if (is_imm) {
|
||||
ri2 = tcg_constant_i64(s->base.pc_next + imm * 2);
|
||||
}
|
||||
|
||||
return ri2;
|
||||
|
Loading…
Reference in New Issue
Block a user