target/mips: add Octeon CRC COP2 helpers

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 <james.hilliard1@gmail.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-ID: <20260608-mips-octeon-missing-insns-v2-v16-3-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:28 -06:00
committed by Philippe Mathieu-Daudé
parent 3bbe7ae19e
commit e1ac6b2775
2 changed files with 145 additions and 0 deletions

View File

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

View File

@@ -14,3 +14,134 @@
#include "crypto/sm4.h"
#include "qemu/bitops.h"
#include "qemu/host-utils.h"
static 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));
}