aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2025-03-11 18:34:58 -0700
committerRichard Henderson <richard.henderson@linaro.org>2025-04-23 14:08:17 -0700
commit6a9dfe1984b0c593fb0ddb52d4e70832e6201dd6 (patch)
tree07a85614c4d3da1c1733303b014474dd06263b73
parent4ba597c138306450e7fcc50d2dba3bfdad8478c8 (diff)
downloadqemu-6a9dfe1984b0c593fb0ddb52d4e70832e6201dd6.zip
qemu-6a9dfe1984b0c593fb0ddb52d4e70832e6201dd6.tar.gz
qemu-6a9dfe1984b0c593fb0ddb52d4e70832e6201dd6.tar.bz2
accel/tcg: Perform aligned atomic reads in translator_ld
Perform aligned atomic reads in translator_ld, if possible. According to https://lore.kernel.org/qemu-devel/20240607101403.1109-1-jim.shu@sifive.com/ this is required for RISC-V Ziccif. Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
-rw-r--r--accel/tcg/translator.c42
1 files changed, 38 insertions, 4 deletions
diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c
index ef1538b..157be33 100644
--- a/accel/tcg/translator.c
+++ b/accel/tcg/translator.c
@@ -265,12 +265,14 @@ static bool translator_ld(CPUArchState *env, DisasContextBase *db,
if (likely(((base ^ last) & TARGET_PAGE_MASK) == 0)) {
/* Entire read is from the first page. */
- memcpy(dest, host + (pc - base), len);
- return true;
+ goto do_read;
}
if (unlikely(((base ^ pc) & TARGET_PAGE_MASK) == 0)) {
- /* Read begins on the first page and extends to the second. */
+ /*
+ * Read begins on the first page and extends to the second.
+ * The unaligned read is never atomic.
+ */
size_t len0 = -(pc | TARGET_PAGE_MASK);
memcpy(dest, host + (pc - base), len0);
pc += len0;
@@ -329,7 +331,39 @@ static bool translator_ld(CPUArchState *env, DisasContextBase *db,
host = db->host_addr[1];
}
- memcpy(dest, host + (pc - base), len);
+ do_read:
+ /*
+ * Assume aligned reads should be atomic, if possible.
+ * We're not in a position to jump out with EXCP_ATOMIC.
+ */
+ host += pc - base;
+ switch (len) {
+ case 2:
+ if (QEMU_IS_ALIGNED(pc, 2)) {
+ uint16_t t = qatomic_read((uint16_t *)host);
+ stw_he_p(dest, t);
+ return true;
+ }
+ break;
+ case 4:
+ if (QEMU_IS_ALIGNED(pc, 4)) {
+ uint32_t t = qatomic_read((uint32_t *)host);
+ stl_he_p(dest, t);
+ return true;
+ }
+ break;
+#ifdef CONFIG_ATOMIC64
+ case 8:
+ if (QEMU_IS_ALIGNED(pc, 8)) {
+ uint64_t t = qatomic_read__nocheck((uint64_t *)host);
+ stq_he_p(dest, t);
+ return true;
+ }
+ break;
+#endif
+ }
+ /* Unaligned or partial read from the second page is not atomic. */
+ memcpy(dest, host, len);
return true;
}