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>
This commit is contained in:
James Hilliard
2026-06-08 12:59:33 -06:00
committed by Philippe Mathieu-Daudé
parent e3ba2fd89c
commit 9bf93903f7
2 changed files with 149 additions and 0 deletions

View File

@@ -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)

View File

@@ -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);