Add the Octeon SHA3 register-window state and helper operations. Keep the
shared HSH/SHA3/SHA512 write path coherent, model the dedicated 25-lane
Keccak state, and implement the Keccak-f[1600] permutation for the
STARTOP selector.

The shared selector window still uses explicit selector-position
arithmetic internally because multiple COP2 engines alias the same numeric
window. Individual DMFC2/DMTC2 instruction decode stays outside the helper
implementation.

Signed-off-by: James Hilliard <[email protected]>
---
Changes v8 -> v9:
  - Split SHA3 selector operations into their own COP2 helper patch.
  - Replace generic selector dispatch with per-operation SHA3 helpers.
  - Use helper-local selector constants for shared-window position logic.
  - Add matching helper.h declarations with the helper implementation.

Changes v1 -> v2:
  - Use switch ranges and g_assert_not_reached() for SHA3 selector
    position decoding.  (suggested by Philippe Mathieu-Daudé)
  - Add selector dispatch updates in octeon_translate.c after moving
    COP2 decode out of translate.c.  (suggested by Philippe
    Mathieu-Daudé)

Changes v5 -> v6:
  - Rename SHA3 DAT15 selector aliases with MF/MT direction suffixes.
---
 target/mips/helper.h            |  22 +++++
 target/mips/tcg/octeon_crypto.c | 172 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 194 insertions(+)

diff --git a/target/mips/helper.h b/target/mips/helper.h
index 7767556f79..31363fb8dd 100644
--- a/target/mips/helper.h
+++ b/target/mips/helper.h
@@ -27,6 +27,7 @@ DEF_HELPER_FLAGS_4(rotx, TCG_CALL_NO_RWG_SE, tl, tl, i32, 
i32, i32)
 
 /* Octeon COP2 selector operation helpers. */
 DEF_HELPER_1(octeon_cp2_mf_crc_iv_reflect, i64, env)
+DEF_HELPER_1(octeon_cp2_mf_sha3_dat24, i64, env)
 DEF_HELPER_2(octeon_cp2_mt_crc_write_iv_reflect, void, env, i64)
 DEF_HELPER_2(octeon_cp2_mt_crc_write_byte, void, env, i64)
 DEF_HELPER_2(octeon_cp2_mt_crc_write_half, void, env, i64)
@@ -42,6 +43,27 @@ DEF_HELPER_2(octeon_cp2_mt_gfm_xor0_reflect, void, env, i64)
 DEF_HELPER_2(octeon_cp2_mt_gfm_xor0, void, env, i64)
 DEF_HELPER_2(octeon_cp2_mt_gfm_xormul1_reflect, void, env, i64)
 DEF_HELPER_2(octeon_cp2_mt_gfm_xormul1, void, env, i64)
+DEF_HELPER_2(octeon_cp2_mt_sha3_dat24, void, env, i64)
+DEF_HELPER_2(octeon_cp2_mt_sha3_dat15, void, env, i64)
+DEF_HELPER_2(octeon_cp2_mt_sha3_xordat0, void, env, i64)
+DEF_HELPER_2(octeon_cp2_mt_sha3_xordat1, void, env, i64)
+DEF_HELPER_2(octeon_cp2_mt_sha3_xordat2, void, env, i64)
+DEF_HELPER_2(octeon_cp2_mt_sha3_xordat3, void, env, i64)
+DEF_HELPER_2(octeon_cp2_mt_sha3_xordat4, void, env, i64)
+DEF_HELPER_2(octeon_cp2_mt_sha3_xordat5, void, env, i64)
+DEF_HELPER_2(octeon_cp2_mt_sha3_xordat6, void, env, i64)
+DEF_HELPER_2(octeon_cp2_mt_sha3_xordat7, void, env, i64)
+DEF_HELPER_2(octeon_cp2_mt_sha3_xordat8, void, env, i64)
+DEF_HELPER_2(octeon_cp2_mt_sha3_xordat9, void, env, i64)
+DEF_HELPER_2(octeon_cp2_mt_sha3_xordat10, void, env, i64)
+DEF_HELPER_2(octeon_cp2_mt_sha3_xordat11, void, env, i64)
+DEF_HELPER_2(octeon_cp2_mt_sha3_xordat12, void, env, i64)
+DEF_HELPER_2(octeon_cp2_mt_sha3_xordat13, void, env, i64)
+DEF_HELPER_2(octeon_cp2_mt_sha3_xordat14, void, env, i64)
+DEF_HELPER_2(octeon_cp2_mt_sha3_xordat15, void, env, i64)
+DEF_HELPER_2(octeon_cp2_mt_sha3_xordat16, void, env, i64)
+DEF_HELPER_2(octeon_cp2_mt_sha3_xordat17, void, env, i64)
+DEF_HELPER_2(octeon_cp2_mt_sha3_startop, 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 d59bd8fdac..010baf3664 100644
--- a/target/mips/tcg/octeon_crypto.c
+++ b/target/mips/tcg/octeon_crypto.c
@@ -16,6 +16,8 @@
 #include "qemu/bitops.h"
 #include "qemu/host-utils.h"
 
+#define OCTEON_SHA3_DAT15 15
+
 static inline uint32_t octeon_crc_reflect32_by_byte(uint32_t v)
 {
     return bswap32(revbit32(v));
@@ -166,11 +168,129 @@ static void octeon_gfm_mul_reflect(MIPSOcteonCryptoState 
*crypto)
     crypto->gfm_reflect_resinp[1] = revbit64(out[1]);
 }
 
+static const uint64_t octeon_sha3_round_constants[24] = {
+    0x0000000000000001ULL, 0x0000000000008082ULL,
+    0x800000000000808aULL, 0x8000000080008000ULL,
+    0x000000000000808bULL, 0x0000000080000001ULL,
+    0x8000000080008081ULL, 0x8000000000008009ULL,
+    0x000000000000008aULL, 0x0000000000000088ULL,
+    0x0000000080008009ULL, 0x000000008000000aULL,
+    0x000000008000808bULL, 0x800000000000008bULL,
+    0x8000000000008089ULL, 0x8000000000008003ULL,
+    0x8000000000008002ULL, 0x8000000000000080ULL,
+    0x000000000000800aULL, 0x800000008000000aULL,
+    0x8000000080008081ULL, 0x8000000000008080ULL,
+    0x0000000080000001ULL, 0x8000000080008008ULL,
+};
+
+static const uint8_t octeon_sha3_rotation_constants[24] = {
+     1,  3,  6, 10, 15, 21, 28, 36, 45, 55,  2, 14,
+    27, 41, 56,  8, 25, 43, 62, 18, 39, 61, 20, 44,
+};
+
+static const uint8_t octeon_sha3_pi_lanes[24] = {
+    10,  7, 11, 17, 18,  3,  5, 16,  8, 21, 24,  4,
+    15, 23, 19, 13, 12,  2, 20, 14, 22,  9,  6,  1,
+};
+
+static uint64_t octeon_sha3_reg_to_lane(uint64_t value)
+{
+    /*
+     * The COP2 register interface is consumed by big-endian MIPS code as
+     * 64-bit register values, while Keccak lanes are byte-little-endian.
+     */
+    return bswap64(value);
+}
+
+static uint64_t octeon_sha3_lane_to_reg(uint64_t value)
+{
+    return bswap64(value);
+}
+
+static uint64_t octeon_sha3_get_lane(MIPSOcteonCryptoState *crypto,
+                                     unsigned int index)
+{
+    if (index < 16) {
+        return octeon_sha3_reg_to_lane(crypto->hsh_dat[index]);
+    }
+    if (index < 24) {
+        return octeon_sha3_reg_to_lane(crypto->hsh_iv[index - 16]);
+    }
+    return octeon_sha3_reg_to_lane(crypto->sha3_dat24);
+}
+
+static void octeon_sha3_set_lane(MIPSOcteonCryptoState *crypto,
+                                 unsigned int index, uint64_t value)
+{
+    value = octeon_sha3_lane_to_reg(value);
+    if (index < 16) {
+        crypto->hsh_dat[index] = value;
+    } else if (index < 24) {
+        crypto->hsh_iv[index - 16] = value;
+    } else {
+        crypto->sha3_dat24 = value;
+    }
+}
+
+static void octeon_sha3_permute(MIPSOcteonCryptoState *crypto)
+{
+    uint64_t state[25];
+
+    for (int i = 0; i < 25; i++) {
+        state[i] = octeon_sha3_get_lane(crypto, i);
+    }
+
+    for (int round = 0; round < 24; round++) {
+        uint64_t bc[5];
+        uint64_t temp;
+
+        for (int x = 0; x < 5; x++) {
+            bc[x] = state[x] ^ state[5 + x] ^ state[10 + x] ^
+                    state[15 + x] ^ state[20 + x];
+        }
+        for (int x = 0; x < 5; x++) {
+            temp = bc[(x + 4) % 5] ^ rol64(bc[(x + 1) % 5], 1);
+            for (int y = 0; y < 25; y += 5) {
+                state[y + x] ^= temp;
+            }
+        }
+
+        temp = state[1];
+        for (int i = 0; i < 24; i++) {
+            uint64_t next = state[octeon_sha3_pi_lanes[i]];
+
+            state[octeon_sha3_pi_lanes[i]] =
+                rol64(temp, octeon_sha3_rotation_constants[i]);
+            temp = next;
+        }
+
+        for (int y = 0; y < 25; y += 5) {
+            for (int x = 0; x < 5; x++) {
+                bc[x] = state[y + x];
+            }
+            for (int x = 0; x < 5; x++) {
+                state[y + x] = bc[x] ^ ((~bc[(x + 1) % 5]) & bc[(x + 2) % 5]);
+            }
+        }
+
+        state[0] ^= octeon_sha3_round_constants[round];
+    }
+
+    for (int i = 0; i < 25; i++) {
+        octeon_sha3_set_lane(crypto, i, state[i]);
+    }
+}
+
 uint64_t helper_octeon_cp2_mf_crc_iv_reflect(CPUMIPSState *env)
 {
     return octeon_crc_reflect32_by_byte(env->octeon_crypto.crc_iv);
 }
 
+uint64_t helper_octeon_cp2_mf_sha3_dat24(CPUMIPSState *env)
+{
+    return env->octeon_crypto.sha3_dat24;
+}
+
 void helper_octeon_cp2_mt_gfm_xor0_reflect(CPUMIPSState *env, uint64_t value)
 {
     env->octeon_crypto.gfm_reflect_resinp[0] ^= value;
@@ -205,6 +325,58 @@ void helper_octeon_cp2_mt_gfm_xormul1(CPUMIPSState *env, 
uint64_t value)
     }
 }
 
+void helper_octeon_cp2_mt_sha3_dat24(CPUMIPSState *env, uint64_t value)
+{
+    env->octeon_crypto.sha3_dat24 = value;
+}
+
+void helper_octeon_cp2_mt_sha3_dat15(CPUMIPSState *env, uint64_t value)
+{
+    env->octeon_crypto.hsh_dat[OCTEON_SHA3_DAT15] = value;
+}
+
+static void octeon_sha3_xordat(MIPSOcteonCryptoState *crypto,
+                               unsigned int index, uint64_t value)
+{
+    uint64_t lane = octeon_sha3_get_lane(crypto, index);
+
+    octeon_sha3_set_lane(crypto, index,
+                         lane ^ octeon_sha3_reg_to_lane(value));
+}
+
+#define OCTEON_SHA3_XORDAT_HELPER(N) \
+void helper_octeon_cp2_mt_sha3_xordat ## N(CPUMIPSState *env, uint64_t value) \
+{ \
+    octeon_sha3_xordat(&env->octeon_crypto, N, value); \
+}
+OCTEON_SHA3_XORDAT_HELPER(0)
+OCTEON_SHA3_XORDAT_HELPER(1)
+OCTEON_SHA3_XORDAT_HELPER(2)
+OCTEON_SHA3_XORDAT_HELPER(3)
+OCTEON_SHA3_XORDAT_HELPER(4)
+OCTEON_SHA3_XORDAT_HELPER(5)
+OCTEON_SHA3_XORDAT_HELPER(6)
+OCTEON_SHA3_XORDAT_HELPER(7)
+OCTEON_SHA3_XORDAT_HELPER(8)
+OCTEON_SHA3_XORDAT_HELPER(9)
+OCTEON_SHA3_XORDAT_HELPER(10)
+OCTEON_SHA3_XORDAT_HELPER(11)
+OCTEON_SHA3_XORDAT_HELPER(12)
+OCTEON_SHA3_XORDAT_HELPER(13)
+OCTEON_SHA3_XORDAT_HELPER(14)
+OCTEON_SHA3_XORDAT_HELPER(15)
+OCTEON_SHA3_XORDAT_HELPER(16)
+OCTEON_SHA3_XORDAT_HELPER(17)
+#undef OCTEON_SHA3_XORDAT_HELPER
+
+void helper_octeon_cp2_mt_sha3_startop(CPUMIPSState *env, uint64_t value)
+{
+    MIPSOcteonCryptoState *crypto = &env->octeon_crypto;
+
+    (void)value;
+    octeon_sha3_permute(crypto);
+}
+
 void helper_octeon_cp2_mt_crc_write_iv_reflect(CPUMIPSState *env,
                                                uint64_t value)
 {

-- 
2.54.0


Reply via email to