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 <james.hilliard1@gmail.com>
---
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 v5 -> v6:
- Rename SHA3 DAT15 selector aliases with MF/MT direction suffixes.
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é)
---
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 9a6702ff60..d1ec75eaff 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_1(octeon_cp2_mf_gfm_mul_reflect0, i64, env)
DEF_HELPER_1(octeon_cp2_mf_gfm_mul_reflect1, i64, env)
DEF_HELPER_1(octeon_cp2_mf_gfm_resinp_reflect0, i64, env)
@@ -48,6 +49,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 b22474574c..b3b88ce018 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));
@@ -149,11 +151,129 @@ static void octeon_gfm_mul64_uia2(const uint64_t x[2], const uint64_t y[2],
out[1] = revbit64(res);
}
+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;
+}
+
uint64_t helper_octeon_cp2_mf_gfm_mul_reflect0(CPUMIPSState *env)
{
return revbit64(env->octeon_crypto.gfm_mul[0]);
@@ -219,6 +339,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