Add helper support for the Octeon AES operation selectors. The direct register-transfer selectors are handled later by the explicit decode patch; this patch adds the ECB/CBC encrypt and decrypt operations that consume the AES input, key, IV, and key-length state.
The AESRESINP direct write path keeps a separate input latch and readback view. Later translator comments document that split where the direct TCG stores are emitted. Signed-off-by: James Hilliard <[email protected]> --- Changes v8 -> v9: - Split AES operation selectors into their own COP2 helper patch. - Replace generic selector dispatch with per-operation AES helpers. - Add matching helper.h declarations with the helper implementation. --- target/mips/cpu.h | 5 ++ target/mips/helper.h | 4 ++ target/mips/tcg/octeon_crypto.c | 141 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 150 insertions(+) diff --git a/target/mips/cpu.h b/target/mips/cpu.h index b57a7a0584..801893b67f 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -556,6 +556,11 @@ typedef struct MIPSOcteonCryptoState { uint64_t sha3_state[25]; uint64_t aes_iv[2]; uint64_t aes_key[4]; + /* + * AESRESINP is one architectural selector bank. Keep a separate input + * latch so operation selectors can consume a pending block while DMFC2 + * reads expose the latest result/readback value. + */ uint64_t aes_result[2]; uint64_t aes_input[2]; uint64_t gfm_mul[2]; diff --git a/target/mips/helper.h b/target/mips/helper.h index 056a9d3fc8..d8ba1f19dd 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -66,6 +66,10 @@ DEF_HELPER_2(octeon_cp2_mt_zuc_start, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_zuc_more, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_snow3g_start, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_snow3g_more, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_aes_enc_cbc1, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_aes_enc1, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_aes_dec_cbc1, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_aes_dec1, 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 ee4d33c24f..55d8818ee2 100644 --- a/target/mips/tcg/octeon_crypto.c +++ b/target/mips/tcg/octeon_crypto.c @@ -763,6 +763,116 @@ static void octeon_snow3g_more(MIPSOcteonCryptoState *crypto) octeon_set_shared_mode(crypto, OCTEON_SHARED_MODE_SNOW3G); octeon_snow3g_queue_result(crypto); } +static int octeon_aes_key_bits(const MIPSOcteonCryptoState *crypto) +{ + enum { + OCTEON_AES_KEYLEN_128 = 1, + OCTEON_AES_KEYLEN_192 = 2, + OCTEON_AES_KEYLEN_256 = 3, + }; + + switch (crypto->aes_keylen) { + case OCTEON_AES_KEYLEN_128: + return 128; + case OCTEON_AES_KEYLEN_192: + return 192; + case OCTEON_AES_KEYLEN_256: + return 256; + default: + return 0; + } +} +static void octeon_aes_load_key(const MIPSOcteonCryptoState *crypto, + uint8_t *key, size_t keylen) +{ + stq_be_p(key, crypto->aes_key[0]); + stq_be_p(key + 8, crypto->aes_key[1]); + if (keylen > 16) { + stq_be_p(key + 16, crypto->aes_key[2]); + } + if (keylen > 24) { + stq_be_p(key + 24, crypto->aes_key[3]); + } +} + +static void octeon_aes_load_block(const uint64_t regs[2], uint8_t *block) +{ + stq_be_p(block, regs[0]); + stq_be_p(block + 8, regs[1]); +} + +static void octeon_aes_store_block(uint64_t regs[2], const uint8_t *block) +{ + regs[0] = ldq_be_p(block); + regs[1] = ldq_be_p(block + 8); +} +static void octeon_aes_encrypt_common(MIPSOcteonCryptoState *crypto, bool cbc) +{ + AES_KEY key; + uint8_t in[16]; + uint8_t out[16]; + uint8_t iv[16]; + uint8_t raw_key[32] = {}; + int bits = octeon_aes_key_bits(crypto); + + if (!bits) { + return; + } + + octeon_aes_load_key(crypto, raw_key, bits / 8); + octeon_aes_load_block(crypto->aes_input, in); + if (cbc) { + int i; + + octeon_aes_load_block(crypto->aes_iv, iv); + for (i = 0; i < sizeof(in); i++) { + in[i] ^= iv[i]; + } + } + + AES_set_encrypt_key(raw_key, bits, &key); + AES_encrypt(in, out, &key); + octeon_aes_store_block(crypto->aes_result, out); + if (cbc) { + octeon_aes_store_block(crypto->aes_iv, out); + } +} + +static void octeon_aes_decrypt_common(MIPSOcteonCryptoState *crypto, bool cbc) +{ + AES_KEY key; + uint8_t in[16]; + uint8_t out[16]; + uint8_t iv[16]; + uint8_t next_iv[16]; + uint8_t raw_key[32] = {}; + int bits = octeon_aes_key_bits(crypto); + int i; + + if (!bits) { + return; + } + + octeon_aes_load_key(crypto, raw_key, bits / 8); + octeon_aes_load_block(crypto->aes_input, in); + if (cbc) { + memcpy(next_iv, in, sizeof(next_iv)); + octeon_aes_load_block(crypto->aes_iv, iv); + } + + AES_set_decrypt_key(raw_key, bits, &key); + AES_decrypt(in, out, &key); + if (cbc) { + for (i = 0; i < sizeof(out); i++) { + out[i] ^= iv[i]; + } + } + + octeon_aes_store_block(crypto->aes_result, out); + if (cbc) { + octeon_aes_store_block(crypto->aes_iv, next_iv); + } +} static void octeon_gfm_mul(const uint64_t x[2], const uint64_t y[2], uint16_t poly, uint64_t out[2]) { @@ -919,6 +1029,37 @@ void helper_octeon_cp2_mt_sha3_startop(CPUMIPSState *env, uint64_t value) octeon_set_shared_mode(crypto, OCTEON_SHARED_MODE_SHA3); octeon_sha3_permute(crypto); } +void helper_octeon_cp2_mt_aes_enc_cbc1(CPUMIPSState *env, uint64_t value) +{ + MIPSOcteonCryptoState *crypto = &env->octeon_crypto; + + crypto->aes_input[1] = value; + octeon_aes_encrypt_common(crypto, true); +} + +void helper_octeon_cp2_mt_aes_enc1(CPUMIPSState *env, uint64_t value) +{ + MIPSOcteonCryptoState *crypto = &env->octeon_crypto; + + crypto->aes_input[1] = value; + octeon_aes_encrypt_common(crypto, false); +} + +void helper_octeon_cp2_mt_aes_dec_cbc1(CPUMIPSState *env, uint64_t value) +{ + MIPSOcteonCryptoState *crypto = &env->octeon_crypto; + + crypto->aes_input[1] = value; + octeon_aes_decrypt_common(crypto, true); +} + +void helper_octeon_cp2_mt_aes_dec1(CPUMIPSState *env, uint64_t value) +{ + MIPSOcteonCryptoState *crypto = &env->octeon_crypto; + + crypto->aes_input[1] = value; + octeon_aes_decrypt_common(crypto, false); +} void helper_octeon_cp2_mt_gfm_xormul1_reflect(CPUMIPSState *env, uint64_t value) { -- 2.54.0
