Hi James,

On 8/6/26 20:59, James Hilliard wrote:
Add helper support for the Octeon HSH hash selectors. This includes the
base HSH data/IV windows, MD5, SHA1, SHA256, and SHA512 transform paths,
and the shared HSH/SHA512 register-window readback and write operations.

The SHA512 path shares the wide HSH register bank with SHA3, SNOW3G, and
ZUC. Keep the aliased readback and write paths centralized so selector
decode can route register accesses through these helpers when side
effects are required.

Signed-off-by: James Hilliard <[email protected]>
---
Changes v13 -> v14:
   - Keep HSH narrow DAT/IV state updates in the low 32-bit halves of the
     architectural HSH register bank so paired selector transfers preserve
     the wide shared-window state.

Changes v10 -> v13:
   - Keep the 0x0057 SDK compatibility path as an explicit STARTSHA1
     compatibility helper instead of a generic STARTSHA name.

Changes v9 -> v10:
   - Remove references to shared-mode tracking; aliased state is kept in the
     architectural HSH register banks.

Changes v8 -> v9:
   - Split HSH/SHA helpers into their own COP2 helper patch.
   - Replace generic selector dispatch with per-operation HSH helpers.
   - Keep shared-window readback and write helpers grouped with HSH.
   - Add matching helper.h declarations with the helper implementation.
---
  target/mips/helper.h            |   5 +
  target/mips/tcg/octeon_crypto.c | 375 ++++++++++++++++++++++++++++++++++++++++
  2 files changed, 380 insertions(+)

diff --git a/target/mips/helper.h b/target/mips/helper.h
index 71b7a2b30e..834f2d0769 100644
--- a/target/mips/helper.h
+++ b/target/mips/helper.h
@@ -69,6 +69,11 @@ DEF_HELPER_2(octeon_cp2_mt_des3_dec, void, env, i64)
  DEF_HELPER_2(octeon_cp2_mt_camellia_fl, void, env, i64)
  DEF_HELPER_2(octeon_cp2_mt_camellia_flinv, void, env, i64)
  DEF_HELPER_2(octeon_cp2_mt_camellia_round, void, env, i64)
+DEF_HELPER_2(octeon_cp2_mt_hsh_startsha1_compat, void, env, i64)
+DEF_HELPER_2(octeon_cp2_mt_hsh_startmd5, void, env, i64)
+DEF_HELPER_2(octeon_cp2_mt_hsh_startsha256, void, env, i64)
+DEF_HELPER_2(octeon_cp2_mt_hsh_startsha, void, env, i64)
+DEF_HELPER_2(octeon_cp2_mt_hsh_startsha512, void, env, i64)
/* microMIPS functions */
  DEF_HELPER_4(lwm, void, env, tl, tl, i32)
diff --git a/target/mips/tcg/octeon_crypto.c b/target/mips/tcg/octeon_crypto.c
index 67959618cc..9523c84667 100644
--- a/target/mips/tcg/octeon_crypto.c
+++ b/target/mips/tcg/octeon_crypto.c
@@ -153,6 +153,348 @@ static void octeon_gfm_mul64_uia2(const uint64_t x[2], 
const uint64_t y[2],
      out[1] = revbit64(res);
  }
+static inline uint32_t octeon_hsh_get32(const uint64_t *regs,
+                                        unsigned int index)
+{
+    return regs[index];
+}
+
+static inline void octeon_hsh_set32(uint64_t *regs, unsigned int index,
+                                    uint32_t value)
+{
+    regs[index] = (regs[index] & ~(uint64_t)UINT32_MAX) | value;
+}
+
+static inline void octeon_hsh_set_pair(uint64_t *regs, unsigned int index,
+                                       uint64_t value)
+{
+    octeon_hsh_set32(regs, index * 2, value >> 32);
+    octeon_hsh_set32(regs, index * 2 + 1, value);
+}
+
+static void octeon_md5_transform(MIPSOcteonCryptoState *crypto)
+{
+    static const uint32_t k[64] = {
+        0xd76aa478U, 0xe8c7b756U, 0x242070dbU, 0xc1bdceeeU,
+        0xf57c0fafU, 0x4787c62aU, 0xa8304613U, 0xfd469501U,
+        0x698098d8U, 0x8b44f7afU, 0xffff5bb1U, 0x895cd7beU,
+        0x6b901122U, 0xfd987193U, 0xa679438eU, 0x49b40821U,
+        0xf61e2562U, 0xc040b340U, 0x265e5a51U, 0xe9b6c7aaU,
+        0xd62f105dU, 0x02441453U, 0xd8a1e681U, 0xe7d3fbc8U,
+        0x21e1cde6U, 0xc33707d6U, 0xf4d50d87U, 0x455a14edU,
+        0xa9e3e905U, 0xfcefa3f8U, 0x676f02d9U, 0x8d2a4c8aU,
+        0xfffa3942U, 0x8771f681U, 0x6d9d6122U, 0xfde5380cU,
+        0xa4beea44U, 0x4bdecfa9U, 0xf6bb4b60U, 0xbebfbc70U,
+        0x289b7ec6U, 0xeaa127faU, 0xd4ef3085U, 0x04881d05U,
+        0xd9d4d039U, 0xe6db99e5U, 0x1fa27cf8U, 0xc4ac5665U,
+        0xf4292244U, 0x432aff97U, 0xab9423a7U, 0xfc93a039U,
+        0x655b59c3U, 0x8f0ccc92U, 0xffeff47dU, 0x85845dd1U,
+        0x6fa87e4fU, 0xfe2ce6e0U, 0xa3014314U, 0x4e0811a1U,
+        0xf7537e82U, 0xbd3af235U, 0x2ad7d2bbU, 0xeb86d391U,
+    };
+    static const uint8_t s[64] = {
+        7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
+        5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
+        4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
+        6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,
+    };
+    uint32_t m[16];
+    uint32_t a, b, c, d;
+    uint32_t aa, bb, cc, dd;
+    int i;
+
+    for (i = 0; i < 16; i++) {
+        m[i] = bswap32(octeon_hsh_get32(crypto->hsh_dat, i));
+    }
+
+    a = bswap32(octeon_hsh_get32(crypto->hsh_iv, 0));
+    b = bswap32(octeon_hsh_get32(crypto->hsh_iv, 1));
+    c = bswap32(octeon_hsh_get32(crypto->hsh_iv, 2));
+    d = bswap32(octeon_hsh_get32(crypto->hsh_iv, 3));

The MD5 algorithm is little-endian, so I think for these we want
cpu_to_le32(), ...

+    aa = a;
+    bb = b;
+    cc = c;
+    dd = d;
+
+    for (i = 0; i < 64; i++) {
+        uint32_t f, g, tmp;
+
+        if (i < 16) {
+            f = (b & c) | ((~b) & d);
+            g = i;
+        } else if (i < 32) {
+            f = (d & b) | ((~d) & c);
+            g = (5 * i + 1) & 0xf;
+        } else if (i < 48) {
+            f = b ^ c ^ d;
+            g = (3 * i + 5) & 0xf;
+        } else {
+            f = c ^ (b | (~d));
+            g = (7 * i) & 0xf;
+        }
+
+        tmp = d;
+        d = c;
+        c = b;
+        b = b + rol32(a + f + k[i] + m[g], s[i]);
+        a = tmp;
+    }
+
+    a += aa;
+    b += bb;
+    c += cc;
+    d += dd;
+    octeon_hsh_set32(crypto->hsh_iv, 0, bswap32(a));
+    octeon_hsh_set32(crypto->hsh_iv, 1, bswap32(b));
+    octeon_hsh_set32(crypto->hsh_iv, 2, bswap32(c));
+    octeon_hsh_set32(crypto->hsh_iv, 3, bswap32(d));

... and le32_to_cpu() here.

+}
+
+static void octeon_sha1_transform(MIPSOcteonCryptoState *crypto)
+{
+    uint32_t w[80];
+    uint32_t a, b, c, d, e;
+    uint32_t orig[5];
+    int i;
+
+    for (i = 0; i < 16; i++) {
+        w[i] = octeon_hsh_get32(crypto->hsh_dat, i);
+    }
+    for (i = 16; i < 80; i++) {
+        w[i] = rol32(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);
+    }
+
+    for (i = 0; i < 5; i++) {
+        orig[i] = octeon_hsh_get32(crypto->hsh_iv, i);
+    }

SHA is big-endian so we are good, but watch out this CPU could switch
endianness.

Maybe safer to use cpu_to_be32() and be32_to_cpu()?

+    a = orig[0];
+    b = orig[1];
+    c = orig[2];
+    d = orig[3];
+    e = orig[4];
+
+    for (i = 0; i < 80; i++) {
+        uint32_t f, k, temp;
+
+        if (i < 20) {
+            f = (b & c) | ((~b) & d);
+            k = 0x5a827999;
+        } else if (i < 40) {
+            f = b ^ c ^ d;
+            k = 0x6ed9eba1;
+        } else if (i < 60) {
+            f = (b & c) | (b & d) | (c & d);
+            k = 0x8f1bbcdc;
+        } else {
+            f = b ^ c ^ d;
+            k = 0xca62c1d6;
+        }
+
+        temp = rol32(a, 5) + f + e + k + w[i];
+        e = d;
+        d = c;
+        c = rol32(b, 30);
+        b = a;
+        a = temp;
+    }
+
+    orig[0] += a;
+    orig[1] += b;
+    orig[2] += c;
+    orig[3] += d;
+    orig[4] += e;
+    for (i = 0; i < 5; i++) {
+        octeon_hsh_set32(crypto->hsh_iv, i, orig[i]);
+    }
+}
+
+static void octeon_sha256_transform(MIPSOcteonCryptoState *crypto)
+{

(ditto)

+}
+
+static void octeon_sha512_transform(MIPSOcteonCryptoState *crypto)
+{

(ditto)

+}

Reply via email to