aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2017-09-04 15:21:56 +0100
committerPeter Maydell <peter.maydell@linaro.org>2017-09-04 17:13:53 +0100
commit3e4d91b94ce400326fae0850578d9e9f30a71adb (patch)
tree9521c8a351f96409beb5fea325d9bb207b7acb7b
parentf58f25599b72c7479e6a1ff67c7f671823aa14da (diff)
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. Cc: qemu-arm@nongnu.org Cc: qemu-stable@nongnu.org Reported-by: Andrew <andrew@fubar.geek.nz> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20170825224833.4463-1-richard.henderson@linaro.org Fixes: https://bugs.launchpad.net/qemu/+bug/1713066 Signed-off-by: Richard Henderson <richard.henderson@linaro.org> [PMM: tweaked comment format] Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--target/arm/translate-a64.c29
1 files changed, 17 insertions, 12 deletions
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index 2200e25be0..cb44632d16 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -2217,29 +2217,34 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn)
} else {
do_fp_st(s, rt, tcg_addr, size);
}
- } else {
- 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_addr, tcg_addr, 1 << size);
- if (is_vector) {
+ tcg_gen_addi_i64(tcg_addr, tcg_addr, 1 << size);
if (is_load) {
do_fp_ld(s, rt2, tcg_addr, size);
} else {
do_fp_st(s, rt2, tcg_addr, size);
}
} else {
+ TCGv_i64 tcg_rt = cpu_reg(s, rt);
TCGv_i64 tcg_rt2 = cpu_reg(s, rt2);
+
if (is_load) {
+ TCGv_i64 tmp = tcg_temp_new_i64();
+
+ /* 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_addr, tcg_addr, 1 << size);
do_gpr_ld(s, tcg_rt2, tcg_addr, size, is_signed, false,
false, 0, false, false);
+
+ tcg_gen_mov_i64(tcg_rt, tmp);
+ tcg_temp_free_i64(tmp);
} else {
+ do_gpr_st(s, tcg_rt, tcg_addr, size,
+ false, 0, false, false);
+ tcg_gen_addi_i64(tcg_addr, tcg_addr, 1 << size);
do_gpr_st(s, tcg_rt2, tcg_addr, size,
false, 0, false, false);
}