target/arm: Fix aa64 ldp register writeback

For "ldp x0, x1, [x0]", if the second load is on a second page and
the second page is unmapped, the exception would be raised with x0
already modified. This means the instruction couldn't be restarted.

Backports commit 2d1bbf51c2cb948da4b6fd5f91cf3ecc80b28156 from qemu
This commit is contained in:
Richard Henderson 2018-03-02 14:35:33 -05:00 committed by Lioncash
parent c27870520a
commit 13242af398
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7

View file

@ -2242,29 +2242,34 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn)
} else { } else {
do_fp_st(s, rt, tcg_addr, size); do_fp_st(s, rt, tcg_addr, size);
} }
} else { tcg_gen_addi_i64(tcg_ctx, tcg_addr, tcg_addr, 1 << size);
TCGv_i64 tcg_rt = cpu_reg(s, rt);
if (is_load) {
do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, false,
false, 0, false, false);
} else {
do_gpr_st(s, tcg_rt, tcg_addr, size,
false, 0, false, false);
}
}
tcg_gen_addi_i64(tcg_ctx, tcg_addr, tcg_addr, 1 << size);
if (is_vector) {
if (is_load) { if (is_load) {
do_fp_ld(s, rt2, tcg_addr, size); do_fp_ld(s, rt2, tcg_addr, size);
} else { } else {
do_fp_st(s, rt2, tcg_addr, size); do_fp_st(s, rt2, tcg_addr, size);
} }
} else { } else {
TCGv_i64 tcg_rt = cpu_reg(s, rt);
TCGv_i64 tcg_rt2 = cpu_reg(s, rt2); TCGv_i64 tcg_rt2 = cpu_reg(s, rt2);
if (is_load) { if (is_load) {
TCGv_i64 tmp = tcg_temp_new_i64(tcg_ctx);
/* Do not modify tcg_rt before recognizing any exception
* from the second load.
*/
do_gpr_ld(s, tmp, tcg_addr, size, is_signed, false,
false, 0, false, false);
tcg_gen_addi_i64(tcg_ctx, tcg_addr, tcg_addr, 1 << size);
do_gpr_ld(s, tcg_rt2, tcg_addr, size, is_signed, false, do_gpr_ld(s, tcg_rt2, tcg_addr, size, is_signed, false,
false, 0, false, false); false, 0, false, false);
tcg_gen_mov_i64(tcg_ctx, tcg_rt, tmp);
tcg_temp_free_i64(tcg_ctx, tmp);
} else { } else {
do_gpr_st(s, tcg_rt, tcg_addr, size,
false, 0, false, false);
tcg_gen_addi_i64(tcg_ctx, tcg_addr, tcg_addr, 1 << size);
do_gpr_st(s, tcg_rt2, tcg_addr, size, do_gpr_st(s, tcg_rt2, tcg_addr, size,
false, 0, false, false); false, 0, false, false);
} }