From: Peter Maydell <peter.maydell@linaro.org>
To: qemu-arm@nongnu.org, qemu-devel@nongnu.org
Subject: [PATCH 1/3] target/arm: Correct LDRD atomicity and fault behaviour
Date: Thu, 27 Feb 2025 14:27:44 +0000 [thread overview]
Message-ID: <20250227142746.1698904-2-peter.maydell@linaro.org> (raw)
In-Reply-To: <20250227142746.1698904-1-peter.maydell@linaro.org>
Our LDRD implementation is wrong in two respects:
* if the address is 4-aligned and the load crosses a page boundary
and the second load faults and the first load was to the
base register (as in cases like "ldrd r2, r3, [r2]", then we
must not update the base register before taking the fault
* if the address is 8-aligned the access must be a 64-bit
single-copy atomic access, not two 32-bit accesses
Rewrite the handling of the loads in LDRD to use a single
tcg_gen_qemu_ld_i64() and split the result into the destination
registers. This allows us to get the atomicity requirements
right, and also implicitly means that we won't update the
base register too early for the page-crossing case.
Note that because we no longer increment 'addr' by 4 in the course of
performing the LDRD we must change the adjustment value we pass to
op_addr_ri_post() and op_addr_rr_post(): it no longer needs to
subtract 4 to get the correct value to use if doing base register
writeback.
STRD has the same problem with not getting the atomicity right;
we will deal with that in the following commit.
Cc: qemu-stable@nongnu.org
Reported-by: Stu Grossman <stu.grossman@gmail.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
target/arm/tcg/translate.c | 64 ++++++++++++++++++++++++--------------
1 file changed, 40 insertions(+), 24 deletions(-)
diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c
index d8225b77c8c..e10a1240c17 100644
--- a/target/arm/tcg/translate.c
+++ b/target/arm/tcg/translate.c
@@ -5003,10 +5003,43 @@ static bool op_store_rr(DisasContext *s, arg_ldst_rr *a,
return true;
}
+static void do_ldrd_load(DisasContext *s, TCGv_i32 addr, int rt, int rt2)
+{
+ /*
+ * LDRD is required to be an atomic 64-bit access if the
+ * address is 8-aligned, two atomic 32-bit accesses if
+ * it's only 4-aligned, and to give an alignemnt fault
+ * if it's not 4-aligned.
+ * Rt is always the word from the lower address, and Rt2 the
+ * data from the higher address, regardless of endianness.
+ * So (like gen_load_exclusive) we avoid gen_aa32_ld_i64()
+ * so we don't get its SCTLR_B check, and instead do a 64-bit access
+ * using MO_BE if appropriate and then split the two halves.
+ *
+ * This also gives us the correct behaviour of not updating
+ * rt if the load of rt2 faults; this is required for cases
+ * like "ldrd r2, r3, [r2]" where rt is also the base register.
+ */
+ int mem_idx = get_mem_index(s);
+ MemOp opc = MO_64 | MO_ALIGN_4 | MO_ATOM_SUBALIGN | s->be_data;
+ TCGv taddr = gen_aa32_addr(s, addr, opc);
+ TCGv_i64 t64 = tcg_temp_new_i64();
+ TCGv_i32 tmp = tcg_temp_new_i32();
+ TCGv_i32 tmp2 = tcg_temp_new_i32();
+
+ tcg_gen_qemu_ld_i64(t64, taddr, mem_idx, opc);
+ if (s->be_data == MO_BE) {
+ tcg_gen_extr_i64_i32(tmp2, tmp, t64);
+ } else {
+ tcg_gen_extr_i64_i32(tmp, tmp2, t64);
+ }
+ store_reg(s, rt, tmp);
+ store_reg(s, rt2, tmp2);
+}
+
static bool trans_LDRD_rr(DisasContext *s, arg_ldst_rr *a)
{
- int mem_idx = get_mem_index(s);
- TCGv_i32 addr, tmp;
+ TCGv_i32 addr;
if (!ENABLE_ARCH_5TE) {
return false;
@@ -5017,18 +5050,10 @@ static bool trans_LDRD_rr(DisasContext *s, arg_ldst_rr *a)
}
addr = op_addr_rr_pre(s, a);
- tmp = tcg_temp_new_i32();
- gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
- store_reg(s, a->rt, tmp);
-
- tcg_gen_addi_i32(addr, addr, 4);
-
- tmp = tcg_temp_new_i32();
- gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
- store_reg(s, a->rt + 1, tmp);
+ do_ldrd_load(s, addr, a->rt, a->rt + 1);
/* LDRD w/ base writeback is undefined if the registers overlap. */
- op_addr_rr_post(s, a, addr, -4);
+ op_addr_rr_post(s, a, addr, 0);
return true;
}
@@ -5152,23 +5177,14 @@ static bool op_store_ri(DisasContext *s, arg_ldst_ri *a,
static bool op_ldrd_ri(DisasContext *s, arg_ldst_ri *a, int rt2)
{
- int mem_idx = get_mem_index(s);
- TCGv_i32 addr, tmp;
+ TCGv_i32 addr;
addr = op_addr_ri_pre(s, a);
- tmp = tcg_temp_new_i32();
- gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
- store_reg(s, a->rt, tmp);
-
- tcg_gen_addi_i32(addr, addr, 4);
-
- tmp = tcg_temp_new_i32();
- gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
- store_reg(s, rt2, tmp);
+ do_ldrd_load(s, addr, a->rt, rt2);
/* LDRD w/ base writeback is undefined if the registers overlap. */
- op_addr_ri_post(s, a, addr, -4);
+ op_addr_ri_post(s, a, addr, 0);
return true;
}
--
2.43.0
next prev parent reply other threads:[~2025-02-27 14:38 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-02-27 14:27 [PATCH 0/3] target/arm: Fix LDRD, STRD atomicity, fault behaviour Peter Maydell
2025-02-27 14:27 ` Peter Maydell [this message]
2025-02-27 17:40 ` [PATCH 1/3] target/arm: Correct LDRD atomicity and " Richard Henderson
2025-02-27 17:58 ` Peter Maydell
2025-02-28 0:18 ` Richard Henderson
2025-02-28 9:37 ` Peter Maydell
2025-02-27 14:27 ` [PATCH 2/3] target/arm: Correct STRD atomicity Peter Maydell
2025-02-27 17:42 ` Richard Henderson
2025-02-27 14:27 ` [PATCH 3/3] target/arm: Drop unused address_offset from op_addr_{rr, ri}_post() Peter Maydell
2025-02-27 17:43 ` Richard Henderson
2025-02-27 22:23 ` Philippe Mathieu-Daudé
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250227142746.1698904-2-peter.maydell@linaro.org \
--to=peter.maydell@linaro.org \
--cc=qemu-arm@nongnu.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).