Commit 9bf93903f7 for qemu.org
commit 9bf93903f715d1188d0a9640f727ffe554fc5b7d
Author: James Hilliard <james.hilliard1@gmail.com>
Date: Mon Jun 8 12:59:33 2026 -0600
target/mips: add Octeon AES COP2 helpers
Add helper support for the Octeon AES operation selectors. Direct
register-transfer selectors do not need helpers; the ECB/CBC encrypt and
decrypt operations consume the AES input, key, IV, and key-length state.
AESRESINP is modeled as one architectural register bank; operation
helpers consume the current AESRESINP block and write the result back to
the same bank.
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
Message-ID: <20260608-mips-octeon-missing-insns-v2-v16-8-daef7a0d8b04@gmail.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
diff --git a/target/mips/helper.h b/target/mips/helper.h
index c4e7693df6..39c226ded9 100644
--- a/target/mips/helper.h
+++ b/target/mips/helper.h
@@ -52,6 +52,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 930a67346e..117e3a5026 100644
--- a/target/mips/tcg/octeon_crypto.c
+++ b/target/mips/tcg/octeon_crypto.c
@@ -840,6 +840,151 @@ static void octeon_snow3g_more(MIPSOcteonCryptoState *crypto)
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_resinp, 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_resinp, 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_resinp, 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_resinp, out);
+ if (cbc) {
+ octeon_aes_store_block(crypto->aes_iv, next_iv);
+ }
+}
+
+void helper_octeon_cp2_mt_aes_enc_cbc1(CPUMIPSState *env, uint64_t value)
+{
+ MIPSOcteonCryptoState *crypto = &env->octeon_crypto;
+
+ crypto->aes_resinp[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_resinp[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_resinp[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_resinp[1] = value;
+ octeon_aes_decrypt_common(crypto, false);
+}
+
void helper_octeon_cp2_mt_snow3g_start(CPUMIPSState *env, uint64_t value)
{
octeon_snow3g_start(&env->octeon_crypto, value);