Add helper support for the Octeon COP2 CRC register interface. This covers normal and reflected CRC state handling, byte/halfword/word/ doubleword/variable-width update selectors, and the reflected IV readback operation.
Register moves that can be represented as direct TCG loads/stores do not need helpers. Add only the side-effecting CRC helper implementation here. Signed-off-by: James Hilliard <[email protected]> Reviewed-by: Richard Henderson <[email protected]> --- Changes v9 -> v10: - Mask variable-length CRC writes to CRCLEN<3:0>. - Add Richard's Reviewed-by tag. Changes v8 -> v9: - Split CRC selector operations into their own COP2 helper patch. - Expose per-operation helpers instead of a generic selector helper. - Add matching helper.h declarations with the helper implementation. --- target/mips/helper.h | 14 +++++ target/mips/tcg/octeon_crypto.c | 131 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+) diff --git a/target/mips/helper.h b/target/mips/helper.h index e2b83a1d19..e802f50fd6 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -25,6 +25,20 @@ DEF_HELPER_3(crc32, tl, tl, tl, i32) DEF_HELPER_3(crc32c, tl, tl, tl, i32) 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_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) +DEF_HELPER_2(octeon_cp2_mt_crc_write_word, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_crc_write_byte_reflect, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_crc_write_half_reflect, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_crc_write_word_reflect, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_crc_write_dword, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_crc_write_var, void, env, i64) +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) + /* microMIPS functions */ DEF_HELPER_4(lwm, void, env, tl, tl, i32) DEF_HELPER_4(swm, void, env, tl, tl, i32) diff --git a/target/mips/tcg/octeon_crypto.c b/target/mips/tcg/octeon_crypto.c index df5b0449ae..811f36f46a 100644 --- a/target/mips/tcg/octeon_crypto.c +++ b/target/mips/tcg/octeon_crypto.c @@ -14,3 +14,134 @@ #include "crypto/sm4.h" #include "qemu/bitops.h" #include "qemu/host-utils.h" + +static inline uint32_t octeon_crc_reflect32_by_byte(uint32_t v) +{ + return bswap32(revbit32(v)); +} + +static uint32_t octeon_crc_state_reflect(const MIPSOcteonCryptoState *crypto) +{ + return octeon_crc_reflect32_by_byte(crypto->crc_iv); +} + +static void octeon_crc_set_state_reflect(MIPSOcteonCryptoState *crypto, + uint32_t state) +{ + crypto->crc_iv = octeon_crc_reflect32_by_byte(state); +} + +static void octeon_crc_update_normal(MIPSOcteonCryptoState *crypto, + uint64_t value, unsigned int bytes) +{ + uint32_t crc = crypto->crc_iv; + uint32_t poly = crypto->crc_poly; + + for (unsigned int i = 0; i < bytes; i++) { + uint8_t byte = value >> ((bytes - 1 - i) * 8); + + crc ^= (uint32_t)byte << 24; + for (int bit = 0; bit < 8; bit++) { + if (crc & 0x80000000U) { + crc = (crc << 1) ^ poly; + } else { + crc <<= 1; + } + } + } + + crypto->crc_iv = crc; +} + +static void octeon_crc_update_reflect(MIPSOcteonCryptoState *crypto, + uint64_t value, unsigned int bytes) +{ + uint32_t crc = octeon_crc_state_reflect(crypto); + uint32_t poly = bswap32(crypto->crc_poly); + + for (unsigned int i = 0; i < bytes; i++) { + uint8_t byte = value >> ((bytes - 1 - i) * 8); + + crc ^= byte; + for (int bit = 0; bit < 8; bit++) { + if (crc & 1U) { + crc = (crc >> 1) ^ poly; + } else { + crc >>= 1; + } + } + } + + octeon_crc_set_state_reflect(crypto, crc); +} + +uint64_t helper_octeon_cp2_mf_crc_iv_reflect(CPUMIPSState *env) +{ + return octeon_crc_reflect32_by_byte(env->octeon_crypto.crc_iv); +} + +void helper_octeon_cp2_mt_crc_write_iv_reflect(CPUMIPSState *env, + uint64_t value) +{ + env->octeon_crypto.crc_iv = + octeon_crc_reflect32_by_byte((uint32_t)value); +} + +void helper_octeon_cp2_mt_crc_write_byte(CPUMIPSState *env, uint64_t value) +{ + octeon_crc_update_normal(&env->octeon_crypto, value, 1); +} + +void helper_octeon_cp2_mt_crc_write_half(CPUMIPSState *env, uint64_t value) +{ + octeon_crc_update_normal(&env->octeon_crypto, value, 2); +} + +void helper_octeon_cp2_mt_crc_write_word(CPUMIPSState *env, uint64_t value) +{ + octeon_crc_update_normal(&env->octeon_crypto, value, 4); +} + +void helper_octeon_cp2_mt_crc_write_dword(CPUMIPSState *env, uint64_t value) +{ + octeon_crc_update_normal(&env->octeon_crypto, value, 8); +} + +void helper_octeon_cp2_mt_crc_write_var(CPUMIPSState *env, uint64_t value) +{ + MIPSOcteonCryptoState *crypto = &env->octeon_crypto; + + octeon_crc_update_normal(crypto, value, MIN(8U, crypto->crc_len & 0xf)); +} + +void helper_octeon_cp2_mt_crc_write_byte_reflect(CPUMIPSState *env, + uint64_t value) +{ + octeon_crc_update_reflect(&env->octeon_crypto, value, 1); +} + +void helper_octeon_cp2_mt_crc_write_half_reflect(CPUMIPSState *env, + uint64_t value) +{ + octeon_crc_update_reflect(&env->octeon_crypto, value, 2); +} + +void helper_octeon_cp2_mt_crc_write_word_reflect(CPUMIPSState *env, + uint64_t value) +{ + octeon_crc_update_reflect(&env->octeon_crypto, value, 4); +} + +void helper_octeon_cp2_mt_crc_write_dword_reflect(CPUMIPSState *env, + uint64_t value) +{ + octeon_crc_update_reflect(&env->octeon_crypto, value, 8); +} + +void helper_octeon_cp2_mt_crc_write_var_reflect(CPUMIPSState *env, + uint64_t value) +{ + MIPSOcteonCryptoState *crypto = &env->octeon_crypto; + + octeon_crc_update_reflect(crypto, value, MIN(8U, crypto->crc_len & 0xf)); +} -- 2.54.0
