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
