On 10/23/26 06:43, Stian Halseth wrote:
On T4 and later, a block-initializing store to the first doubleword of
a 32-byte block zeroes the rest of the block (measured on a T4).
glibc's niagara4 memset and Linux's NG4memset rely on this, and
OpenSSL's T4 AES code uses the FP form, stdfa.

QEMU only accepted the integer form, on HYPV CPUs, as a plain store, so
with the crypto hwcap a multiarch glibc memset leaves stale data. Accept
both forms when the CPU has the crypto feature, which implies T4 or
later, and zero the 32-byte block as T4 does.

Signed-off-by: Stian Halseth <[email protected]>
---
  target/sparc/translate.c | 42 ++++++++++++++++++++++++++++++++++++++--
  1 file changed, 40 insertions(+), 2 deletions(-)

diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index 1fc8439a47..009340a3bb 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -1853,6 +1853,26 @@ static void gen_ld_asi(DisasContext *dc, DisasASI *da, 
TCGv dst, TCGv addr)
      }
  }
+/*
+ * On T4 and later, a block-initializing store to the first doubleword of
+ * a 32-byte block zeroes the rest of the block. glibc and Linux memset
+ * rely on this and store only one doubleword per block when zeroing.
+ */
+static void gen_blkinit_zero(DisasContext *dc, DisasASI *da, TCGv addr)
+{
+    TCGLabel *skip = gen_new_label();
+    TCGv t = tcg_temp_new();
+    TCGv_i64 zero = tcg_constant_i64(0);
+
+    tcg_gen_andi_tl(t, addr, 31);
+    tcg_gen_brcondi_tl(TCG_COND_NE, t, 0, skip);

tcg_gen_brcondi_tl(TCG_COND_TSTNE, addr, 31, skip);

+    for (int i = 0; i < 32; i += 8) {
+        tcg_gen_addi_tl(t, addr, i);
+        tcg_gen_qemu_st_i64(zero, t, da->mem_idx, MO_UQ);
+    }

You don't need to store to offset 0, because...

+    case GET_ASI_DTWINX:
+        /* stdfa with a block-initializing ASI, T4 and later */
+        if (orig_size == MO_64 && (dc->def->features & CPU_FEATURE_CRYPTO)) {
+            gen_blkinit_zero(dc, da, addr);
+            d64 = gen_load_fpr_D(dc, rd);
+            tcg_gen_qemu_st_i64(d64, addr, da->mem_idx, memop | MO_ALIGN);

... that's done here.


r~

Reply via email to