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. Decode of the individual DMFC2/DMTC2 instructions remains in the later decodetree patch. 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/cpu.h | 2 + target/mips/helper.h | 22 +++++ target/mips/system/machine.c | 1 + target/mips/tcg/octeon_crypto.c | 208 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 233 insertions(+) diff --git a/target/mips/cpu.h b/target/mips/cpu.h index 66c8653211..a061a86658 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -541,6 +541,7 @@ typedef enum MIPSOcteonSharedMode { OCTEON_SHARED_MODE_NONE = 0, OCTEON_SHARED_MODE_SHA512, OCTEON_SHARED_MODE_SNOW3G, + OCTEON_SHARED_MODE_SHA3, } MIPSOcteonSharedMode; typedef struct MIPSOcteonCryptoState { @@ -551,6 +552,7 @@ typedef struct MIPSOcteonCryptoState { uint64_t hsh_dat[8]; uint64_t hsh_ivw[8]; uint64_t hsh_datw[16]; + uint64_t sha3_state[25]; uint64_t aes_iv[2]; uint64_t aes_key[4]; uint64_t aes_result[2]; diff --git a/target/mips/helper.h b/target/mips/helper.h index dac9dd8755..c0aa361ad8 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) @@ -40,6 +41,27 @@ DEF_HELPER_2(octeon_cp2_mt_crc_write_dword_reflect, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_crc_write_var_reflect, 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/system/machine.c b/target/mips/system/machine.c index ebfa0a9eb0..e6336534f4 100644 --- a/target/mips/system/machine.c +++ b/target/mips/system/machine.c @@ -292,6 +292,7 @@ static const VMStateDescription mips_vmstate_octeon_crypto = { VMSTATE_UINT64_ARRAY(env.octeon_crypto.hsh_dat, MIPSCPU, 8), VMSTATE_UINT64_ARRAY(env.octeon_crypto.hsh_ivw, MIPSCPU, 8), VMSTATE_UINT64_ARRAY(env.octeon_crypto.hsh_datw, MIPSCPU, 16), + VMSTATE_UINT64_ARRAY(env.octeon_crypto.sha3_state, MIPSCPU, 25), VMSTATE_UINT64_ARRAY(env.octeon_crypto.aes_iv, MIPSCPU, 2), VMSTATE_UINT64_ARRAY(env.octeon_crypto.aes_key, MIPSCPU, 4), VMSTATE_UINT64_ARRAY(env.octeon_crypto.aes_result, MIPSCPU, 2), diff --git a/target/mips/tcg/octeon_crypto.c b/target/mips/tcg/octeon_crypto.c index 7394108c54..caad685cde 100644 --- a/target/mips/tcg/octeon_crypto.c +++ b/target/mips/tcg/octeon_crypto.c @@ -136,6 +136,140 @@ static void octeon_gfm_mul_reflect(MIPSOcteonCryptoState *crypto, uint64_t data) crypto->gfm_poly, crypto->gfm_reflect_resinp); crypto->gfm_reflect_xor0 = 0; } +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 void octeon_sha3_permute(MIPSOcteonCryptoState *crypto) +{ + uint64_t *state = crypto->sha3_state; + + 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]; + } +} + +static bool octeon_sha3_is_dat_sel(uint32_t sel) +{ + switch (sel) { + case OCTEON_HSH_DATW(0) ... OCTEON_HSH_DATW(15): + case OCTEON_HSH_IVW(0) ... OCTEON_HSH_IVW(7): + case OCTEON_SHA3_DAT15_MT_SEL: + case OCTEON_SHA3_DAT24_SEL: + return true; + default: + return false; + } +} + +static int octeon_sha3_dat_pos_from_sel(uint32_t sel) +{ + switch (sel) { + case OCTEON_HSH_DATW(0) ... OCTEON_HSH_DATW(14): + return sel - OCTEON_HSH_DATW(0); + case OCTEON_HSH_IVW(0) ... OCTEON_HSH_IVW(7): + return 16 + (sel - OCTEON_HSH_IVW(0)); + case OCTEON_HSH_DATW(15): + case OCTEON_SHA3_DAT15_MT_SEL: + return 15; + case OCTEON_SHA3_DAT24_SEL: + return 24; + default: + g_assert_not_reached(); + } +} + +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 void octeon_store_shared_hsh_window(MIPSOcteonCryptoState *crypto, + uint32_t sel, uint64_t value) +{ + switch (sel) { + case OCTEON_HSH_DATW(0) ... OCTEON_HSH_DATW(14): + crypto->hsh_datw[sel - OCTEON_HSH_DATW(0)] = value; + crypto->sha3_state[sel - OCTEON_HSH_DATW(0)] = + octeon_sha3_reg_to_lane(value); + break; + case OCTEON_HSH_IVW(0) ... OCTEON_HSH_IVW(7): + crypto->hsh_ivw[sel - OCTEON_HSH_IVW(0)] = value; + crypto->sha3_state[16 + (sel - OCTEON_HSH_IVW(0))] = + octeon_sha3_reg_to_lane(value); + break; + case OCTEON_SHA3_DAT15_MT_SEL: + crypto->sha3_state[15] = octeon_sha3_reg_to_lane(value); + break; + case OCTEON_SHA3_DAT24_SEL: + crypto->sha3_state[24] = octeon_sha3_reg_to_lane(value); + break; + default: + g_assert_not_reached(); + } +} static void octeon_gfm_mul(const uint64_t x[2], const uint64_t y[2], uint16_t poly, uint64_t out[2]) { @@ -169,10 +303,84 @@ static void octeon_gfm_mul(const uint64_t x[2], const uint64_t y[2], out[0] = zh; out[1] = zl; } +uint64_t helper_octeon_cp2_mf_sha3_dat24(CPUMIPSState *env) +{ + MIPSOcteonCryptoState *crypto = &env->octeon_crypto; + + if (crypto->shared_mode == OCTEON_SHARED_MODE_SHA3) { + return octeon_sha3_lane_to_reg(crypto->sha3_state[24]); + } + return 0; +} uint64_t helper_octeon_cp2_mf_crc_iv_reflect(CPUMIPSState *env) { return octeon_crc_reflect32_by_byte(env->octeon_crypto.crc_iv); } +static void octeon_sha3_mt_dat(MIPSOcteonCryptoState *crypto, + uint32_t sel, uint64_t value) +{ + if (crypto->shared_mode == OCTEON_SHARED_MODE_ZUC && + octeon_zuc_is_shared_dmtc2_sel(sel)) { + octeon_store_shared_hsh_window(crypto, sel, value); + return; + } + + octeon_set_shared_mode(crypto, OCTEON_SHARED_MODE_SHA3); + octeon_store_shared_hsh_window(crypto, sel, value); +} + +void helper_octeon_cp2_mt_sha3_dat24(CPUMIPSState *env, uint64_t value) +{ + octeon_sha3_mt_dat(&env->octeon_crypto, OCTEON_SHA3_DAT24_SEL, + value); +} + +void helper_octeon_cp2_mt_sha3_dat15(CPUMIPSState *env, uint64_t value) +{ + octeon_sha3_mt_dat(&env->octeon_crypto, OCTEON_SHA3_DAT15_MT_SEL, + value); +} + +static void octeon_sha3_xordat(MIPSOcteonCryptoState *crypto, + unsigned int index, uint64_t value) +{ + octeon_set_shared_mode(crypto, OCTEON_SHARED_MODE_SHA3); + crypto->sha3_state[index] ^= 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_set_shared_mode(crypto, OCTEON_SHARED_MODE_SHA3); + octeon_sha3_permute(crypto); +} void helper_octeon_cp2_mt_gfm_xormul1_reflect(CPUMIPSState *env, uint64_t value) { -- 2.54.0
