From 304df6d35eb660883ac8a59968cce5cb2bddd060 Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Mon, 8 Jun 2026 12:59:26 -0600 Subject: [PATCH 01/23] target/mips: add Octeon COP2 crypto state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the common architectural state needed by Octeon's selector-driven COP2 crypto interfaces. This includes storage for the base hash, AES, CRC, GFM, 3DES, KASUMI, and overlapping HSH/SHA512/SHA3/SNOW3G/ZUC selector windows. Keep selector values and helper-local aliasing logic out of the CPU state header so the state definition remains limited to architectural storage. Helper code uses the same register banks instead of adding non-architectural shadow state. Model the SHA3 view as a direct 25-lane alias of the architectural HSH DAT/IV/SHA3_DAT24 storage. Migrate the state in an Octeon-only subsection so non-Octeon CPU models do not grow migration data. Signed-off-by: James Hilliard Reviewed-by: Richard Henderson Message-ID: <20260608-mips-octeon-missing-insns-v2-v16-1-daef7a0d8b04@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- target/mips/cpu.h | 26 ++++++++++++++++++++++++++ target/mips/system/machine.c | 27 +++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/target/mips/cpu.h b/target/mips/cpu.h index 392406aff8..3df71adf9b 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -537,6 +537,30 @@ struct TCState { }; struct MIPSITUState; +typedef struct MIPSOcteonCryptoState { + union { + struct { + uint64_t hsh_dat[16]; + uint64_t hsh_iv[8]; + uint64_t sha3_dat24; + }; + uint64_t sha3_dat[25]; + }; + uint64_t des3_key[3]; + uint64_t des3_iv; + uint64_t des3_result; + uint64_t aes_resinp[2]; + uint64_t aes_iv[2]; + uint64_t aes_key[4]; + uint32_t crc_poly; + uint32_t crc_iv; + uint64_t gfm_mul[2]; + uint64_t gfm_resinp[2]; + uint16_t gfm_poly; + uint8_t aes_keylen; + uint8_t crc_len; +} MIPSOcteonCryptoState; + typedef struct CPUArchState { TCState active_tc; CPUMIPSFPUContext active_fpu; @@ -558,6 +582,8 @@ typedef struct CPUArchState { #define MSAIR_ProcID 8 #define MSAIR_Rev 0 + MIPSOcteonCryptoState octeon_crypto; + /* * CP0 Register 0 */ diff --git a/target/mips/system/machine.c b/target/mips/system/machine.c index f988b3695b..77f576a25b 100644 --- a/target/mips/system/machine.c +++ b/target/mips/system/machine.c @@ -279,6 +279,32 @@ static const VMStateDescription mips_vmstate_octeon_multiplier = { } }; +static const VMStateDescription mips_vmstate_octeon_crypto = { + .name = "cpu/octeon_crypto", + .version_id = 1, + .minimum_version_id = 1, + .needed = mips_octeon_needed, + .fields = (const VMStateField[]) { + VMSTATE_UINT64_ARRAY(env.octeon_crypto.hsh_dat, MIPSCPU, 16), + VMSTATE_UINT64_ARRAY(env.octeon_crypto.hsh_iv, MIPSCPU, 8), + VMSTATE_UINT64(env.octeon_crypto.sha3_dat24, MIPSCPU), + VMSTATE_UINT64_ARRAY(env.octeon_crypto.des3_key, MIPSCPU, 3), + VMSTATE_UINT64(env.octeon_crypto.des3_iv, MIPSCPU), + VMSTATE_UINT64(env.octeon_crypto.des3_result, MIPSCPU), + VMSTATE_UINT64_ARRAY(env.octeon_crypto.aes_resinp, MIPSCPU, 2), + VMSTATE_UINT64_ARRAY(env.octeon_crypto.aes_iv, MIPSCPU, 2), + VMSTATE_UINT64_ARRAY(env.octeon_crypto.aes_key, MIPSCPU, 4), + VMSTATE_UINT32(env.octeon_crypto.crc_poly, MIPSCPU), + VMSTATE_UINT32(env.octeon_crypto.crc_iv, MIPSCPU), + VMSTATE_UINT64_ARRAY(env.octeon_crypto.gfm_mul, MIPSCPU, 2), + VMSTATE_UINT64_ARRAY(env.octeon_crypto.gfm_resinp, MIPSCPU, 2), + VMSTATE_UINT16(env.octeon_crypto.gfm_poly, MIPSCPU), + VMSTATE_UINT8(env.octeon_crypto.aes_keylen, MIPSCPU), + VMSTATE_UINT8(env.octeon_crypto.crc_len, MIPSCPU), + VMSTATE_END_OF_LIST() + } +}; + const VMStateDescription vmstate_mips_cpu = { .name = "cpu", .version_id = 21, @@ -396,6 +422,7 @@ const VMStateDescription vmstate_mips_cpu = { .subsections = (const VMStateDescription * const []) { &mips_vmstate_timer, &mips_vmstate_octeon_multiplier, + &mips_vmstate_octeon_crypto, NULL } }; From 3bbe7ae19e2bd87302043a341b01d58b77786738 Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Mon, 8 Jun 2026 12:59:27 -0600 Subject: [PATCH 02/23] target/mips: add Octeon COP2 crypto helper plumbing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the Octeon COP2 crypto helper source file and build it with the MIPS TCG target. This provides the common compilation unit for the COP2 engine helpers. The instruction dispatch itself remains fully decoded by decodetree, and operation selectors call per-operation helpers rather than a common selector-dispatch helper. Signed-off-by: James Hilliard Reviewed-by: Richard Henderson Message-ID: <20260608-mips-octeon-missing-insns-v2-v16-2-daef7a0d8b04@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- target/mips/tcg/meson.build | 1 + target/mips/tcg/octeon_crypto.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 target/mips/tcg/octeon_crypto.c diff --git a/target/mips/tcg/meson.build b/target/mips/tcg/meson.build index fff9cd6c7f..4ee359874a 100644 --- a/target/mips/tcg/meson.build +++ b/target/mips/tcg/meson.build @@ -18,6 +18,7 @@ mips_ss.add(files( 'lmmi_helper.c', 'msa_helper.c', 'msa_translate.c', + 'octeon_crypto.c', 'op_helper.c', 'rel6_translate.c', 'translate.c', diff --git a/target/mips/tcg/octeon_crypto.c b/target/mips/tcg/octeon_crypto.c new file mode 100644 index 0000000000..df5b0449ae --- /dev/null +++ b/target/mips/tcg/octeon_crypto.c @@ -0,0 +1,16 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * MIPS Octeon crypto emulation helpers. + * + * Copyright (c) 2026 James Hilliard + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "internal.h" +#include "exec/helper-proto.h" +#include "crypto/aes.h" +#include "crypto/sm4.h" +#include "qemu/bitops.h" +#include "qemu/host-utils.h" From e1ac6b277591a2e00233fad10d8736a97f07598e Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Mon, 8 Jun 2026 12:59:28 -0600 Subject: [PATCH 03/23] target/mips: add Octeon CRC COP2 helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Richard Henderson Message-ID: <20260608-mips-octeon-missing-insns-v2-v16-3-daef7a0d8b04@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- 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..c589077ea7 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 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)); +} From c69401bbf659be4de8e699a7e0d230051c0e4765 Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Mon, 8 Jun 2026 12:59:29 -0600 Subject: [PATCH 04/23] target/mips: add Octeon GFM COP2 helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add helper support for the Octeon GFM carryless multiply selectors. This models the normal and reflected multiplication paths, including the XOR-and-multiply forms that update the result/input state used by Octeon crypto code. Reflected selectors operate on the architectural GFM register bank using bit-reflected register transfers rather than a separate shadow state. Keep the 64-bit UIA2 reduction path used by SNOW3G F9 and share that shortcut between the normal and reflected XORMUL1 paths. Signed-off-by: James Hilliard Message-ID: <20260608-mips-octeon-missing-insns-v2-v16-4-daef7a0d8b04@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- target/mips/helper.h | 9 ++ target/mips/tcg/octeon_crypto.c | 142 ++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+) diff --git a/target/mips/helper.h b/target/mips/helper.h index e802f50fd6..20ffbfb709 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -27,6 +27,10 @@ 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_1(octeon_cp2_mf_gfm_mul_reflect0, i64, env) +DEF_HELPER_1(octeon_cp2_mf_gfm_mul_reflect1, i64, env) +DEF_HELPER_1(octeon_cp2_mf_gfm_resinp_reflect0, i64, env) +DEF_HELPER_1(octeon_cp2_mf_gfm_resinp_reflect1, 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) @@ -38,6 +42,11 @@ 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) +DEF_HELPER_2(octeon_cp2_mt_gfm_mul_reflect0, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_gfm_mul_reflect1, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_gfm_xor0_reflect, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_gfm_xormul1_reflect, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_gfm_xormul1, 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 c589077ea7..b417dcf53b 100644 --- a/target/mips/tcg/octeon_crypto.c +++ b/target/mips/tcg/octeon_crypto.c @@ -11,6 +11,7 @@ #include "internal.h" #include "exec/helper-proto.h" #include "crypto/aes.h" +#include "crypto/clmul.h" #include "crypto/sm4.h" #include "qemu/bitops.h" #include "qemu/host-utils.h" @@ -75,11 +76,152 @@ static void octeon_crc_update_reflect(MIPSOcteonCryptoState *crypto, octeon_crc_set_state_reflect(crypto, crc); } +static void octeon_gfm_mul(const uint64_t x[2], const uint64_t y[2], + uint16_t poly, uint64_t out[2]) +{ + uint64_t zh = 0, zl = 0; + uint64_t vh = y[0], vl = y[1]; + uint64_t rh = (uint64_t)poly << 48; + int i; + + /* + * Keep the reflected-shift formulation used by Octeon software: the + * selector polynomial is already in reflected bit order, and the software + * view folds its 16 reduction bits from the top of the high word. + */ + for (i = 0; i < 128; i++) { + bool bit; + bool lsb; + + if (i < 64) { + bit = (x[0] >> (63 - i)) & 1; + } else { + bit = (x[1] >> (127 - i)) & 1; + } + if (bit) { + zh ^= vh; + zl ^= vl; + } + + lsb = vl & 1; + vl = (vh << 63) | (vl >> 1); + vh >>= 1; + if (lsb) { + vh ^= rh; + } + } + + out[0] = zh; + out[1] = zl; +} + +static uint64_t octeon_gfm_reduce64(Int128 product, uint8_t poly) +{ + uint64_t lo = int128_getlo(product); + uint64_t hi = int128_gethi(product); + + while (hi) { + int bit = 63 - clz64(hi); + + hi ^= 1ULL << bit; + lo ^= (uint64_t)poly << bit; + if (bit > 56) { + hi ^= (uint64_t)poly >> (64 - bit); + } + } + + return lo; +} + +static void octeon_gfm_mul64_uia2(const uint64_t x[2], const uint64_t y[2], + uint8_t poly, uint64_t out[2]) +{ + /* + * SNOW3G UIA2 uses the GFM datapath as a reflected 64-bit multiply in + * the low half of the 128-bit register pair. When RESINP[0], MUL[1], + * and the high polynomial byte are all zero, octeon_gfm_mul() observes + * only x[1], y[0], and the low 8-bit polynomial. Reflect those operands + * into normal carryless-multiply order and reflect the reduced result + * back into RESINP[1]. + */ + uint64_t vx = revbit64(x[1]); + uint64_t vy = revbit64(y[0]); + Int128 product = clmul_64(vx, vy); + uint64_t res = octeon_gfm_reduce64(product, revbit32(poly) >> 24); + + out[0] = 0; + out[1] = revbit64(res); +} + uint64_t helper_octeon_cp2_mf_crc_iv_reflect(CPUMIPSState *env) { return octeon_crc_reflect32_by_byte(env->octeon_crypto.crc_iv); } +uint64_t helper_octeon_cp2_mf_gfm_mul_reflect0(CPUMIPSState *env) +{ + return revbit64(env->octeon_crypto.gfm_mul[0]); +} + +uint64_t helper_octeon_cp2_mf_gfm_mul_reflect1(CPUMIPSState *env) +{ + return revbit64(env->octeon_crypto.gfm_mul[1]); +} + +uint64_t helper_octeon_cp2_mf_gfm_resinp_reflect0(CPUMIPSState *env) +{ + return revbit64(env->octeon_crypto.gfm_resinp[0]); +} + +uint64_t helper_octeon_cp2_mf_gfm_resinp_reflect1(CPUMIPSState *env) +{ + return revbit64(env->octeon_crypto.gfm_resinp[1]); +} + +void helper_octeon_cp2_mt_gfm_mul_reflect0(CPUMIPSState *env, uint64_t value) +{ + env->octeon_crypto.gfm_mul[0] = revbit64(value); +} + +void helper_octeon_cp2_mt_gfm_mul_reflect1(CPUMIPSState *env, uint64_t value) +{ + env->octeon_crypto.gfm_mul[1] = revbit64(value); +} + +void helper_octeon_cp2_mt_gfm_xor0_reflect(CPUMIPSState *env, uint64_t value) +{ + env->octeon_crypto.gfm_resinp[0] ^= revbit64(value); +} + +static void octeon_gfm_xormul1_common(MIPSOcteonCryptoState *crypto, + uint64_t value) +{ + crypto->gfm_resinp[1] ^= value; + if (crypto->gfm_poly <= 0xff && crypto->gfm_mul[1] == 0 && + crypto->gfm_resinp[0] == 0) { + octeon_gfm_mul64_uia2(crypto->gfm_resinp, crypto->gfm_mul, + crypto->gfm_poly, crypto->gfm_resinp); + } else { + octeon_gfm_mul(crypto->gfm_resinp, crypto->gfm_mul, crypto->gfm_poly, + crypto->gfm_resinp); + } +} + +void helper_octeon_cp2_mt_gfm_xormul1_reflect(CPUMIPSState *env, + uint64_t value) +{ + MIPSOcteonCryptoState *crypto = &env->octeon_crypto; + + octeon_gfm_xormul1_common(crypto, revbit64(value)); +} + +void helper_octeon_cp2_mt_gfm_xormul1(CPUMIPSState *env, uint64_t value) +{ + MIPSOcteonCryptoState *crypto = &env->octeon_crypto; + + octeon_gfm_xormul1_common(crypto, value); +} + void helper_octeon_cp2_mt_crc_write_iv_reflect(CPUMIPSState *env, uint64_t value) { From 20d1f0e84238f0a0c4d7937204252c3d52e1731f Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Mon, 8 Jun 2026 12:59:30 -0600 Subject: [PATCH 05/23] target/mips: add Octeon SHA3 COP2 helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the Octeon SHA3 helper operations for the architectural 25-lane Keccak state view and implement the Keccak-f[1600] permutation used by the STARTOP selector. The simple SHA3 DAT register moves and XORDAT selectors are decoded as direct TCG transfers in the selector decode patch. This helper patch only keeps the side-effecting SHA3 operation support. Signed-off-by: James Hilliard Message-ID: <20260608-mips-octeon-missing-insns-v2-v16-5-daef7a0d8b04@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- target/mips/helper.h | 1 + target/mips/tcg/octeon_crypto.c | 93 +++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/target/mips/helper.h b/target/mips/helper.h index 20ffbfb709..b887e05199 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -47,6 +47,7 @@ DEF_HELPER_2(octeon_cp2_mt_gfm_mul_reflect1, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_gfm_xor0_reflect, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_gfm_xormul1_reflect, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_gfm_xormul1, void, env, i64) +DEF_HELPER_1(octeon_cp2_mt_sha3_startop, void, env) /* 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 b417dcf53b..cf718d6482 100644 --- a/target/mips/tcg/octeon_crypto.c +++ b/target/mips/tcg/octeon_crypto.c @@ -153,6 +153,94 @@ static void octeon_gfm_mul64_uia2(const uint64_t x[2], const uint64_t y[2], out[1] = revbit64(res); } +static const uint64_t octeon_sha3_round_constants[24] = { + 0x0000000000000001ULL, 0x0000000000008082ULL, + 0x800000000000808aULL, 0x8000000080008000ULL, + 0x000000000000808bULL, 0x0000000080000001ULL, + 0x8000000080008081ULL, 0x8000000000008009ULL, + 0x000000000000008aULL, 0x0000000000000088ULL, + 0x0000000080008009ULL, 0x000000008000000aULL, + 0x000000008000808bULL, 0x800000000000008bULL, + 0x8000000000008089ULL, 0x8000000000008003ULL, + 0x8000000000008002ULL, 0x8000000000000080ULL, + 0x000000000000800aULL, 0x800000008000000aULL, + 0x8000000080008081ULL, 0x8000000000008080ULL, + 0x0000000080000001ULL, 0x8000000080008008ULL, +}; + +static const uint8_t octeon_sha3_rotation_constants[24] = { + 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44, +}; + +static const uint8_t octeon_sha3_pi_lanes[24] = { + 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1, +}; + +static uint64_t octeon_sha3_reg_to_lane(uint64_t value) +{ + /* + * The COP2 register interface is consumed by big-endian MIPS code as + * 64-bit register values, while Keccak lanes are byte-little-endian. + */ + return bswap64(value); +} + +static uint64_t octeon_sha3_lane_to_reg(uint64_t value) +{ + return bswap64(value); +} + +static void octeon_sha3_permute(MIPSOcteonCryptoState *crypto) +{ + uint64_t state[25]; + + for (int i = 0; i < 25; i++) { + state[i] = octeon_sha3_reg_to_lane(crypto->sha3_dat[i]); + } + + for (int round = 0; round < 24; round++) { + uint64_t bc[5]; + uint64_t temp; + + for (int x = 0; x < 5; x++) { + bc[x] = state[x] ^ state[5 + x] ^ state[10 + x] ^ + state[15 + x] ^ state[20 + x]; + } + for (int x = 0; x < 5; x++) { + temp = bc[(x + 4) % 5] ^ rol64(bc[(x + 1) % 5], 1); + for (int y = 0; y < 25; y += 5) { + state[y + x] ^= temp; + } + } + + temp = state[1]; + for (int i = 0; i < 24; i++) { + uint64_t next = state[octeon_sha3_pi_lanes[i]]; + + state[octeon_sha3_pi_lanes[i]] = + rol64(temp, octeon_sha3_rotation_constants[i]); + temp = next; + } + + for (int y = 0; y < 25; y += 5) { + for (int x = 0; x < 5; x++) { + bc[x] = state[y + x]; + } + for (int x = 0; x < 5; x++) { + state[y + x] = bc[x] ^ ((~bc[(x + 1) % 5]) & bc[(x + 2) % 5]); + } + } + + state[0] ^= octeon_sha3_round_constants[round]; + } + + for (int i = 0; i < 25; i++) { + crypto->sha3_dat[i] = octeon_sha3_lane_to_reg(state[i]); + } +} + uint64_t helper_octeon_cp2_mf_crc_iv_reflect(CPUMIPSState *env) { return octeon_crc_reflect32_by_byte(env->octeon_crypto.crc_iv); @@ -222,6 +310,11 @@ void helper_octeon_cp2_mt_gfm_xormul1(CPUMIPSState *env, uint64_t value) octeon_gfm_xormul1_common(crypto, value); } +void helper_octeon_cp2_mt_sha3_startop(CPUMIPSState *env) +{ + octeon_sha3_permute(&env->octeon_crypto); +} + void helper_octeon_cp2_mt_crc_write_iv_reflect(CPUMIPSState *env, uint64_t value) { From 27ab71de26aa4fbf7bbddc68c6147b554e969c2d Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Mon, 8 Jun 2026 12:59:31 -0600 Subject: [PATCH 06/23] target/mips: add Octeon ZUC COP2 helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the Octeon ZUC START and MORE helper operations and model the shared state window used by the hardware interface. This covers the keystream and MAC engine state, including the save-and-restore view that overlaps the HSH/SHA3 bank. Keep the LFSR words in the architectural HSH DAT input registers and the runtime MAC/FSM/result state in the documented HASHIV window. The third MAC lookahead word is generated on demand instead of being kept in a non-architectural shadow slot. Signed-off-by: James Hilliard Message-ID: <20260608-mips-octeon-missing-insns-v2-v16-6-daef7a0d8b04@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- target/mips/helper.h | 2 + target/mips/tcg/octeon_crypto.c | 338 ++++++++++++++++++++++++++++++++ 2 files changed, 340 insertions(+) diff --git a/target/mips/helper.h b/target/mips/helper.h index b887e05199..292336ec62 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -48,6 +48,8 @@ DEF_HELPER_2(octeon_cp2_mt_gfm_xor0_reflect, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_gfm_xormul1_reflect, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_gfm_xormul1, void, env, i64) DEF_HELPER_1(octeon_cp2_mt_sha3_startop, void, env) +DEF_HELPER_2(octeon_cp2_mt_zuc_start, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_zuc_more, 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 cf718d6482..548269b9b8 100644 --- a/target/mips/tcg/octeon_crypto.c +++ b/target/mips/tcg/octeon_crypto.c @@ -241,6 +241,344 @@ static void octeon_sha3_permute(MIPSOcteonCryptoState *crypto) } } +static uint32_t octeon_crypto_hi32(uint64_t value) +{ + return value >> 32; +} + +static uint32_t octeon_crypto_lo32(uint64_t value) +{ + return value; +} + +static const uint8_t octeon_zuc_s0[256] = { + 0x3e, 0x72, 0x5b, 0x47, 0xca, 0xe0, 0x00, 0x33, + 0x04, 0xd1, 0x54, 0x98, 0x09, 0xb9, 0x6d, 0xcb, + 0x7b, 0x1b, 0xf9, 0x32, 0xaf, 0x9d, 0x6a, 0xa5, + 0xb8, 0x2d, 0xfc, 0x1d, 0x08, 0x53, 0x03, 0x90, + 0x4d, 0x4e, 0x84, 0x99, 0xe4, 0xce, 0xd9, 0x91, + 0xdd, 0xb6, 0x85, 0x48, 0x8b, 0x29, 0x6e, 0xac, + 0xcd, 0xc1, 0xf8, 0x1e, 0x73, 0x43, 0x69, 0xc6, + 0xb5, 0xbd, 0xfd, 0x39, 0x63, 0x20, 0xd4, 0x38, + 0x76, 0x7d, 0xb2, 0xa7, 0xcf, 0xed, 0x57, 0xc5, + 0xf3, 0x2c, 0xbb, 0x14, 0x21, 0x06, 0x55, 0x9b, + 0xe3, 0xef, 0x5e, 0x31, 0x4f, 0x7f, 0x5a, 0xa4, + 0x0d, 0x82, 0x51, 0x49, 0x5f, 0xba, 0x58, 0x1c, + 0x4a, 0x16, 0xd5, 0x17, 0xa8, 0x92, 0x24, 0x1f, + 0x8c, 0xff, 0xd8, 0xae, 0x2e, 0x01, 0xd3, 0xad, + 0x3b, 0x4b, 0xda, 0x46, 0xeb, 0xc9, 0xde, 0x9a, + 0x8f, 0x87, 0xd7, 0x3a, 0x80, 0x6f, 0x2f, 0xc8, + 0xb1, 0xb4, 0x37, 0xf7, 0x0a, 0x22, 0x13, 0x28, + 0x7c, 0xcc, 0x3c, 0x89, 0xc7, 0xc3, 0x96, 0x56, + 0x07, 0xbf, 0x7e, 0xf0, 0x0b, 0x2b, 0x97, 0x52, + 0x35, 0x41, 0x79, 0x61, 0xa6, 0x4c, 0x10, 0xfe, + 0xbc, 0x26, 0x95, 0x88, 0x8a, 0xb0, 0xa3, 0xfb, + 0xc0, 0x18, 0x94, 0xf2, 0xe1, 0xe5, 0xe9, 0x5d, + 0xd0, 0xdc, 0x11, 0x66, 0x64, 0x5c, 0xec, 0x59, + 0x42, 0x75, 0x12, 0xf5, 0x74, 0x9c, 0xaa, 0x23, + 0x0e, 0x86, 0xab, 0xbe, 0x2a, 0x02, 0xe7, 0x67, + 0xe6, 0x44, 0xa2, 0x6c, 0xc2, 0x93, 0x9f, 0xf1, + 0xf6, 0xfa, 0x36, 0xd2, 0x50, 0x68, 0x9e, 0x62, + 0x71, 0x15, 0x3d, 0xd6, 0x40, 0xc4, 0xe2, 0x0f, + 0x8e, 0x83, 0x77, 0x6b, 0x25, 0x05, 0x3f, 0x0c, + 0x30, 0xea, 0x70, 0xb7, 0xa1, 0xe8, 0xa9, 0x65, + 0x8d, 0x27, 0x1a, 0xdb, 0x81, 0xb3, 0xa0, 0xf4, + 0x45, 0x7a, 0x19, 0xdf, 0xee, 0x78, 0x34, 0x60, +}; + +static const uint8_t octeon_zuc_s1[256] = { + 0x55, 0xc2, 0x63, 0x71, 0x3b, 0xc8, 0x47, 0x86, + 0x9f, 0x3c, 0xda, 0x5b, 0x29, 0xaa, 0xfd, 0x77, + 0x8c, 0xc5, 0x94, 0x0c, 0xa6, 0x1a, 0x13, 0x00, + 0xe3, 0xa8, 0x16, 0x72, 0x40, 0xf9, 0xf8, 0x42, + 0x44, 0x26, 0x68, 0x96, 0x81, 0xd9, 0x45, 0x3e, + 0x10, 0x76, 0xc6, 0xa7, 0x8b, 0x39, 0x43, 0xe1, + 0x3a, 0xb5, 0x56, 0x2a, 0xc0, 0x6d, 0xb3, 0x05, + 0x22, 0x66, 0xbf, 0xdc, 0x0b, 0xfa, 0x62, 0x48, + 0xdd, 0x20, 0x11, 0x06, 0x36, 0xc9, 0xc1, 0xcf, + 0xf6, 0x27, 0x52, 0xbb, 0x69, 0xf5, 0xd4, 0x87, + 0x7f, 0x84, 0x4c, 0xd2, 0x9c, 0x57, 0xa4, 0xbc, + 0x4f, 0x9a, 0xdf, 0xfe, 0xd6, 0x8d, 0x7a, 0xeb, + 0x2b, 0x53, 0xd8, 0x5c, 0xa1, 0x14, 0x17, 0xfb, + 0x23, 0xd5, 0x7d, 0x30, 0x67, 0x73, 0x08, 0x09, + 0xee, 0xb7, 0x70, 0x3f, 0x61, 0xb2, 0x19, 0x8e, + 0x4e, 0xe5, 0x4b, 0x93, 0x8f, 0x5d, 0xdb, 0xa9, + 0xad, 0xf1, 0xae, 0x2e, 0xcb, 0x0d, 0xfc, 0xf4, + 0x2d, 0x46, 0x6e, 0x1d, 0x97, 0xe8, 0xd1, 0xe9, + 0x4d, 0x37, 0xa5, 0x75, 0x5e, 0x83, 0x9e, 0xab, + 0x82, 0x9d, 0xb9, 0x1c, 0xe0, 0xcd, 0x49, 0x89, + 0x01, 0xb6, 0xbd, 0x58, 0x24, 0xa2, 0x5f, 0x38, + 0x78, 0x99, 0x15, 0x90, 0x50, 0xb8, 0x95, 0xe4, + 0xd0, 0x91, 0xc7, 0xce, 0xed, 0x0f, 0xb4, 0x6f, + 0xa0, 0xcc, 0xf0, 0x02, 0x4a, 0x79, 0xc3, 0xde, + 0xa3, 0xef, 0xea, 0x51, 0xe6, 0x6b, 0x18, 0xec, + 0x1b, 0x2c, 0x80, 0xf7, 0x74, 0xe7, 0xff, 0x21, + 0x5a, 0x6a, 0x54, 0x1e, 0x41, 0x31, 0x92, 0x35, + 0xc4, 0x33, 0x07, 0x0a, 0xba, 0x7e, 0x0e, 0x34, + 0x88, 0xb1, 0x98, 0x7c, 0xf3, 0x3d, 0x60, 0x6c, + 0x7b, 0xca, 0xd3, 0x1f, 0x32, 0x65, 0x04, 0x28, + 0x64, 0xbe, 0x85, 0x9b, 0x2f, 0x59, 0x8a, 0xd7, + 0xb0, 0x25, 0xac, 0xaf, 0x12, 0x03, 0xe2, 0xf2, +}; + +static uint32_t octeon_zuc_addm(uint32_t a, uint32_t b) +{ + uint32_t c = a + b; + + c = (c & 0x7fffffffU) + (c >> 31); + return c ? c : 0x7fffffffU; +} + +static uint32_t octeon_zuc_mul_by_pow2(uint32_t v, unsigned int shift) +{ + return ((v << shift) | (v >> (31 - shift))) & 0x7fffffffU; +} + +static uint32_t octeon_zuc_make_u32(uint8_t a, uint8_t b, uint8_t c, uint8_t d) +{ + return ((uint32_t)a << 24) | ((uint32_t)b << 16) | + ((uint32_t)c << 8) | d; +} + +static uint64_t octeon_zuc_pack_pair(uint32_t hi, uint32_t lo) +{ + return ((uint64_t)hi << 32) | lo; +} + +static uint32_t octeon_zuc_lfsr(const MIPSOcteonCryptoState *crypto, + unsigned int index) +{ + uint64_t pair = crypto->hsh_dat[index / 2]; + + return index & 1 ? octeon_crypto_lo32(pair) : octeon_crypto_hi32(pair); +} + +static void octeon_zuc_set_lfsr(MIPSOcteonCryptoState *crypto, + unsigned int index, uint32_t value) +{ + uint32_t hi = octeon_crypto_hi32(crypto->hsh_dat[index / 2]); + uint32_t lo = octeon_crypto_lo32(crypto->hsh_dat[index / 2]); + + value &= 0x7fffffffU; + if (index & 1) { + lo = value; + } else { + hi = value; + } + crypto->hsh_dat[index / 2] = octeon_zuc_pack_pair(hi, lo); +} + +static uint32_t octeon_zuc_fsm(const MIPSOcteonCryptoState *crypto, + unsigned int index) +{ + g_assert(index < 2); + return crypto->hsh_iv[1 + index]; +} + +static void octeon_zuc_set_fsm(MIPSOcteonCryptoState *crypto, + unsigned int index, uint32_t value) +{ + g_assert(index < 2); + crypto->hsh_iv[1 + index] = value; +} + +static uint32_t octeon_zuc_window(const MIPSOcteonCryptoState *crypto, + unsigned int index) +{ + uint64_t pair = crypto->hsh_iv[0]; + + switch (index) { + case 0: + return octeon_crypto_hi32(pair); + case 1: + return octeon_crypto_lo32(pair); + default: + g_assert_not_reached(); + } +} + +static void octeon_zuc_set_window_pair(MIPSOcteonCryptoState *crypto, + uint32_t hi, uint32_t lo) +{ + crypto->hsh_iv[0] = octeon_zuc_pack_pair(hi, lo); +} + +static uint32_t octeon_zuc_tresult(const MIPSOcteonCryptoState *crypto) +{ + return crypto->hsh_iv[3]; +} + +static void octeon_zuc_set_tresult(MIPSOcteonCryptoState *crypto, + uint32_t value) +{ + crypto->hsh_iv[3] = value; +} + +static void octeon_zuc_bit_reorganization(const MIPSOcteonCryptoState *crypto, + uint32_t x[4]) +{ + x[0] = ((octeon_zuc_lfsr(crypto, 15) & 0x7fff8000U) << 1) | + (octeon_zuc_lfsr(crypto, 14) & 0xffffU); + x[1] = ((octeon_zuc_lfsr(crypto, 11) & 0xffffU) << 16) | + (octeon_zuc_lfsr(crypto, 9) >> 15); + x[2] = ((octeon_zuc_lfsr(crypto, 7) & 0xffffU) << 16) | + (octeon_zuc_lfsr(crypto, 5) >> 15); + x[3] = ((octeon_zuc_lfsr(crypto, 2) & 0xffffU) << 16) | + (octeon_zuc_lfsr(crypto, 0) >> 15); +} + +static uint32_t octeon_zuc_l1(uint32_t x) +{ + return x ^ rol32(x, 2) ^ rol32(x, 10) ^ rol32(x, 18) ^ rol32(x, 24); +} + +static uint32_t octeon_zuc_l2(uint32_t x) +{ + return x ^ rol32(x, 8) ^ rol32(x, 14) ^ rol32(x, 22) ^ rol32(x, 30); +} + +static uint32_t octeon_zuc_f(MIPSOcteonCryptoState *crypto, const uint32_t x[4]) +{ + uint32_t fsm0 = octeon_zuc_fsm(crypto, 0); + uint32_t fsm1 = octeon_zuc_fsm(crypto, 1); + uint32_t w = (x[0] ^ fsm0) + fsm1; + uint32_t w1 = fsm0 + x[1]; + uint32_t w2 = fsm1 ^ x[2]; + uint32_t u = octeon_zuc_l1((w1 << 16) | (w2 >> 16)); + uint32_t v = octeon_zuc_l2((w2 << 16) | (w1 >> 16)); + + octeon_zuc_set_fsm(crypto, 0, + octeon_zuc_make_u32(octeon_zuc_s0[u >> 24], + octeon_zuc_s1[(uint8_t)(u >> 16)], + octeon_zuc_s0[(uint8_t)(u >> 8)], + octeon_zuc_s1[(uint8_t)u])); + octeon_zuc_set_fsm(crypto, 1, + octeon_zuc_make_u32(octeon_zuc_s0[v >> 24], + octeon_zuc_s1[(uint8_t)(v >> 16)], + octeon_zuc_s0[(uint8_t)(v >> 8)], + octeon_zuc_s1[(uint8_t)v])); + return w; +} + +static void octeon_zuc_lfsr_step(MIPSOcteonCryptoState *crypto, + bool init_mode, uint32_t u) +{ + uint32_t lfsr[16]; + uint32_t f; + + for (int i = 0; i < 16; i++) { + lfsr[i] = octeon_zuc_lfsr(crypto, i); + } + + f = lfsr[0]; + f = octeon_zuc_addm(f, octeon_zuc_mul_by_pow2(lfsr[0], 8)); + f = octeon_zuc_addm(f, octeon_zuc_mul_by_pow2(lfsr[4], 20)); + f = octeon_zuc_addm(f, octeon_zuc_mul_by_pow2(lfsr[10], 21)); + f = octeon_zuc_addm(f, octeon_zuc_mul_by_pow2(lfsr[13], 17)); + f = octeon_zuc_addm(f, octeon_zuc_mul_by_pow2(lfsr[15], 15)); + if (init_mode) { + f = octeon_zuc_addm(f, u); + } + + for (int i = 0; i < 15; i++) { + octeon_zuc_set_lfsr(crypto, i, lfsr[i + 1]); + } + octeon_zuc_set_lfsr(crypto, 15, f); +} + +static uint32_t octeon_zuc_generate_word(MIPSOcteonCryptoState *crypto) +{ + uint32_t x[4]; + uint32_t z; + + octeon_zuc_bit_reorganization(crypto, x); + z = octeon_zuc_f(crypto, x) ^ x[3]; + octeon_zuc_lfsr_step(crypto, false, 0); + return z; +} + +static void octeon_zuc_fill_window_pair(MIPSOcteonCryptoState *crypto) +{ + uint32_t z0 = octeon_zuc_generate_word(crypto); + uint32_t z1 = octeon_zuc_generate_word(crypto); + + octeon_zuc_set_window_pair(crypto, z0, z1); +} + +static uint32_t +octeon_zuc_window_word(const MIPSOcteonCryptoState *crypto, unsigned int bit, + uint32_t z2) +{ + if (bit == 0) { + return octeon_zuc_window(crypto, 0); + } + if (bit < 32) { + return (octeon_zuc_window(crypto, 0) << bit) | + (octeon_zuc_window(crypto, 1) >> (32 - bit)); + } + if (bit == 32) { + return octeon_zuc_window(crypto, 1); + } + return (octeon_zuc_window(crypto, 1) << (bit - 32)) | + (z2 >> (64 - bit)); +} + +static void octeon_zuc_advance_window(MIPSOcteonCryptoState *crypto, + uint32_t z2) +{ + uint32_t z3 = octeon_zuc_generate_word(crypto); + + octeon_zuc_set_window_pair(crypto, z2, z3); +} + +static void octeon_zuc_start(MIPSOcteonCryptoState *crypto, uint64_t data) +{ + uint32_t x[4]; + + for (int i = 0; i < 14; i++) { + octeon_zuc_set_lfsr(crypto, i, octeon_zuc_lfsr(crypto, i)); + } + octeon_zuc_set_lfsr(crypto, 14, data >> 32); + octeon_zuc_set_lfsr(crypto, 15, data); + octeon_zuc_set_fsm(crypto, 0, 0); + octeon_zuc_set_fsm(crypto, 1, 0); + octeon_zuc_set_tresult(crypto, 0); + + for (int i = 0; i < 32; i++) { + octeon_zuc_bit_reorganization(crypto, x); + octeon_zuc_lfsr_step(crypto, true, octeon_zuc_f(crypto, x) >> 1); + } + + octeon_zuc_bit_reorganization(crypto, x); + (void)octeon_zuc_f(crypto, x); + octeon_zuc_lfsr_step(crypto, false, 0); + octeon_zuc_fill_window_pair(crypto); +} + +static void octeon_zuc_more(MIPSOcteonCryptoState *crypto, uint64_t data) +{ + uint32_t t = octeon_zuc_tresult(crypto); + uint32_t z2 = octeon_zuc_generate_word(crypto); + + for (unsigned int bit = 0; bit < 64; bit++) { + if ((data >> (63 - bit)) & 1) { + t ^= octeon_zuc_window_word(crypto, bit, z2); + } + } + octeon_zuc_set_tresult(crypto, t); + octeon_zuc_advance_window(crypto, z2); +} + +void helper_octeon_cp2_mt_zuc_start(CPUMIPSState *env, uint64_t value) +{ + octeon_zuc_start(&env->octeon_crypto, value); +} + +void helper_octeon_cp2_mt_zuc_more(CPUMIPSState *env, uint64_t value) +{ + octeon_zuc_more(&env->octeon_crypto, value); +} + uint64_t helper_octeon_cp2_mf_crc_iv_reflect(CPUMIPSState *env) { return octeon_crc_reflect32_by_byte(env->octeon_crypto.crc_iv); From e3ba2fd89c90c6f69023065e7958da4ee8753444 Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Mon, 8 Jun 2026 12:59:32 -0600 Subject: [PATCH 07/23] target/mips: add Octeon SNOW3G COP2 helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add helper support for the Octeon SNOW3G START and MORE selectors. The engine state and result are represented through the architectural HSH IV and DAT register banks that SNOW3G aliases for save and restore. Signed-off-by: James Hilliard Message-ID: <20260608-mips-octeon-missing-insns-v2-v16-7-daef7a0d8b04@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- target/mips/helper.h | 2 + target/mips/tcg/octeon_crypto.c | 282 ++++++++++++++++++++++++++++++++ 2 files changed, 284 insertions(+) diff --git a/target/mips/helper.h b/target/mips/helper.h index 292336ec62..c4e7693df6 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -50,6 +50,8 @@ DEF_HELPER_2(octeon_cp2_mt_gfm_xormul1, void, env, i64) DEF_HELPER_1(octeon_cp2_mt_sha3_startop, void, env) 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) /* 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 548269b9b8..930a67346e 100644 --- a/target/mips/tcg/octeon_crypto.c +++ b/target/mips/tcg/octeon_crypto.c @@ -251,6 +251,11 @@ static uint32_t octeon_crypto_lo32(uint64_t value) return value; } +static uint64_t octeon_crypto_pack32(uint32_t hi, uint32_t lo) +{ + return ((uint64_t)hi << 32) | lo; +} + static const uint8_t octeon_zuc_s0[256] = { 0x3e, 0x72, 0x5b, 0x47, 0xca, 0xe0, 0x00, 0x33, 0x04, 0xd1, 0x54, 0x98, 0x09, 0xb9, 0x6d, 0xcb, @@ -569,6 +574,283 @@ static void octeon_zuc_more(MIPSOcteonCryptoState *crypto, uint64_t data) octeon_zuc_advance_window(crypto, z2); } +static const uint8_t octeon_snow3g_sr[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, + 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, + 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, + 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, + 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, + 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, + 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, + 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, + 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, + 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, + 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, + 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, + 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, + 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, + 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, + 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16, +}; + +static const uint8_t octeon_snow3g_sq[256] = { + 0x25, 0x24, 0x73, 0x67, 0xd7, 0xae, 0x5c, 0x30, + 0xa4, 0xee, 0x6e, 0xcb, 0x7d, 0xb5, 0x82, 0xdb, + 0xe4, 0x8e, 0x48, 0x49, 0x4f, 0x5d, 0x6a, 0x78, + 0x70, 0x88, 0xe8, 0x5f, 0x5e, 0x84, 0x65, 0xe2, + 0xd8, 0xe9, 0xcc, 0xed, 0x40, 0x2f, 0x11, 0x28, + 0x57, 0xd2, 0xac, 0xe3, 0x4a, 0x15, 0x1b, 0xb9, + 0xb2, 0x80, 0x85, 0xa6, 0x2e, 0x02, 0x47, 0x29, + 0x07, 0x4b, 0x0e, 0xc1, 0x51, 0xaa, 0x89, 0xd4, + 0xca, 0x01, 0x46, 0xb3, 0xef, 0xdd, 0x44, 0x7b, + 0xc2, 0x7f, 0xbe, 0xc3, 0x9f, 0x20, 0x4c, 0x64, + 0x83, 0xa2, 0x68, 0x42, 0x13, 0xb4, 0x41, 0xcd, + 0xba, 0xc6, 0xbb, 0x6d, 0x4d, 0x71, 0x21, 0xf4, + 0x8d, 0xb0, 0xe5, 0x93, 0xfe, 0x8f, 0xe6, 0xcf, + 0x43, 0x45, 0x31, 0x22, 0x37, 0x36, 0x96, 0xfa, + 0xbc, 0x0f, 0x08, 0x52, 0x1d, 0x55, 0x1a, 0xc5, + 0x4e, 0x23, 0x69, 0x7a, 0x92, 0xff, 0x5b, 0x5a, + 0xeb, 0x9a, 0x1c, 0xa9, 0xd1, 0x7e, 0x0d, 0xfc, + 0x50, 0x8a, 0xb6, 0x62, 0xf5, 0x0a, 0xf8, 0xdc, + 0x03, 0x3c, 0x0c, 0x39, 0xf1, 0xb8, 0xf3, 0x3d, + 0xf2, 0xd5, 0x97, 0x66, 0x81, 0x32, 0xa0, 0x00, + 0x06, 0xce, 0xf6, 0xea, 0xb7, 0x17, 0xf7, 0x8c, + 0x79, 0xd6, 0xa7, 0xbf, 0x8b, 0x3f, 0x1f, 0x53, + 0x63, 0x75, 0x35, 0x2c, 0x60, 0xfd, 0x27, 0xd3, + 0x94, 0xa5, 0x7c, 0xa1, 0x05, 0x58, 0x2d, 0xbd, + 0xd9, 0xc7, 0xaf, 0x6b, 0x54, 0x0b, 0xe0, 0x38, + 0x04, 0xc8, 0x9d, 0xe7, 0x14, 0xb1, 0x87, 0x9c, + 0xdf, 0x6f, 0xf9, 0xda, 0x2a, 0xc4, 0x59, 0x16, + 0x74, 0x91, 0xab, 0x26, 0x61, 0x76, 0x34, 0x2b, + 0xad, 0x99, 0xfb, 0x72, 0xec, 0x33, 0x12, 0xde, + 0x98, 0x3b, 0xc0, 0x9b, 0x3e, 0x18, 0x10, 0x3a, + 0x56, 0xe1, 0x77, 0xc9, 0x1e, 0x9e, 0x95, 0xa3, + 0x90, 0x19, 0xa8, 0x6c, 0x09, 0xd0, 0xf0, 0x86, +}; + +static uint8_t octeon_snow3g_mulx(uint8_t v, uint8_t c) +{ + return (v & 0x80) ? ((v << 1) ^ c) : (v << 1); +} + +static uint8_t octeon_snow3g_mulxpow(uint8_t v, unsigned int n, uint8_t c) +{ + while (n-- > 0) { + v = octeon_snow3g_mulx(v, c); + } + return v; +} + +static uint32_t octeon_snow3g_pack32(uint8_t b0, uint8_t b1, + uint8_t b2, uint8_t b3) +{ + return ((uint32_t)b0 << 24) + | ((uint32_t)b1 << 16) + | ((uint32_t)b2 << 8) + | b3; +} + +static uint32_t octeon_snow3g_mulalpha(uint8_t c) +{ + return octeon_snow3g_pack32(octeon_snow3g_mulxpow(c, 23, 0xa9), + octeon_snow3g_mulxpow(c, 245, 0xa9), + octeon_snow3g_mulxpow(c, 48, 0xa9), + octeon_snow3g_mulxpow(c, 239, 0xa9)); +} + +static uint32_t octeon_snow3g_divalpha(uint8_t c) +{ + return octeon_snow3g_pack32(octeon_snow3g_mulxpow(c, 16, 0xa9), + octeon_snow3g_mulxpow(c, 39, 0xa9), + octeon_snow3g_mulxpow(c, 6, 0xa9), + octeon_snow3g_mulxpow(c, 64, 0xa9)); +} + +static uint32_t octeon_snow3g_s1(uint32_t w) +{ + uint8_t x0 = octeon_snow3g_sr[w >> 24]; + uint8_t x1 = octeon_snow3g_sr[(uint8_t)(w >> 16)]; + uint8_t x2 = octeon_snow3g_sr[(uint8_t)(w >> 8)]; + uint8_t x3 = octeon_snow3g_sr[(uint8_t)w]; + uint8_t r0 = octeon_snow3g_mulx(x0, 0x1b) ^ x1 ^ x2 ^ + octeon_snow3g_mulx(x3, 0x1b) ^ x3; + uint8_t r1 = octeon_snow3g_mulx(x0, 0x1b) ^ x0 ^ + octeon_snow3g_mulx(x1, 0x1b) ^ x2 ^ x3; + uint8_t r2 = x0 ^ octeon_snow3g_mulx(x1, 0x1b) ^ x1 ^ + octeon_snow3g_mulx(x2, 0x1b) ^ x3; + uint8_t r3 = x0 ^ x1 ^ octeon_snow3g_mulx(x2, 0x1b) ^ x2 ^ + octeon_snow3g_mulx(x3, 0x1b); + + return octeon_snow3g_pack32(r0, r1, r2, r3); +} + +static uint32_t octeon_snow3g_s2(uint32_t w) +{ + uint8_t x0 = octeon_snow3g_sq[w >> 24]; + uint8_t x1 = octeon_snow3g_sq[(uint8_t)(w >> 16)]; + uint8_t x2 = octeon_snow3g_sq[(uint8_t)(w >> 8)]; + uint8_t x3 = octeon_snow3g_sq[(uint8_t)w]; + uint8_t r0 = octeon_snow3g_mulx(x0, 0x69) ^ x1 ^ x2 ^ + octeon_snow3g_mulx(x3, 0x69) ^ x3; + uint8_t r1 = octeon_snow3g_mulx(x0, 0x69) ^ x0 ^ + octeon_snow3g_mulx(x1, 0x69) ^ x2 ^ x3; + uint8_t r2 = x0 ^ octeon_snow3g_mulx(x1, 0x69) ^ x1 ^ + octeon_snow3g_mulx(x2, 0x69) ^ x3; + uint8_t r3 = x0 ^ x1 ^ octeon_snow3g_mulx(x2, 0x69) ^ x2 ^ + octeon_snow3g_mulx(x3, 0x69); + + return octeon_snow3g_pack32(r0, r1, r2, r3); +} + +static uint32_t octeon_snow3g_lfsr(const MIPSOcteonCryptoState *crypto, + unsigned int index) +{ + uint64_t pair = crypto->hsh_dat[index / 2]; + + return index & 1 ? octeon_crypto_lo32(pair) : octeon_crypto_hi32(pair); +} + +static void octeon_snow3g_set_lfsr(MIPSOcteonCryptoState *crypto, + unsigned int index, uint32_t value) +{ + uint32_t hi = octeon_crypto_hi32(crypto->hsh_dat[index / 2]); + uint32_t lo = octeon_crypto_lo32(crypto->hsh_dat[index / 2]); + + if (index & 1) { + lo = value; + } else { + hi = value; + } + crypto->hsh_dat[index / 2] = octeon_crypto_pack32(hi, lo); +} + +static uint32_t octeon_snow3g_fsm(const MIPSOcteonCryptoState *crypto, + unsigned int index) +{ + return crypto->hsh_iv[1 + index]; +} + +static void octeon_snow3g_set_fsm(MIPSOcteonCryptoState *crypto, + unsigned int index, uint32_t value) +{ + crypto->hsh_iv[1 + index] = value; +} + +static uint32_t octeon_snow3g_clock_fsm(MIPSOcteonCryptoState *crypto) +{ + uint32_t fsm0 = octeon_snow3g_fsm(crypto, 0); + uint32_t fsm1 = octeon_snow3g_fsm(crypto, 1); + uint32_t fsm2 = octeon_snow3g_fsm(crypto, 2); + uint32_t f = (uint32_t)(octeon_snow3g_lfsr(crypto, 15) + fsm0) ^ fsm1; + uint32_t r = (uint32_t)(fsm1 + (fsm2 ^ octeon_snow3g_lfsr(crypto, 5))); + + octeon_snow3g_set_fsm(crypto, 2, octeon_snow3g_s2(fsm1)); + octeon_snow3g_set_fsm(crypto, 1, octeon_snow3g_s1(fsm0)); + octeon_snow3g_set_fsm(crypto, 0, r); + return f; +} + +static void octeon_snow3g_clock_lfsr(MIPSOcteonCryptoState *crypto, + bool init_mode, uint32_t f) +{ + uint32_t lfsr[16]; + uint32_t s0; + uint32_t s11; + uint32_t v; + int i; + + for (i = 0; i < 16; i++) { + lfsr[i] = octeon_snow3g_lfsr(crypto, i); + } + + s0 = lfsr[0]; + s11 = lfsr[11]; + v = (s0 << 8) ^ octeon_snow3g_mulalpha(s0 >> 24) ^ + lfsr[2] ^ (s11 >> 8) ^ octeon_snow3g_divalpha((uint8_t)s11); + + if (init_mode) { + v ^= f; + } + + for (i = 0; i < 15; i++) { + octeon_snow3g_set_lfsr(crypto, i, lfsr[i + 1]); + } + octeon_snow3g_set_lfsr(crypto, 15, v); +} + +static uint32_t octeon_snow3g_generate_word(MIPSOcteonCryptoState *crypto) +{ + uint32_t f = octeon_snow3g_clock_fsm(crypto); + uint32_t z = f ^ octeon_snow3g_lfsr(crypto, 0); + + octeon_snow3g_clock_lfsr(crypto, false, 0); + return z; +} + +static void octeon_snow3g_queue_result(MIPSOcteonCryptoState *crypto) +{ + uint32_t z0 = octeon_snow3g_generate_word(crypto); + uint32_t z1 = octeon_snow3g_generate_word(crypto); + + crypto->hsh_iv[0] = octeon_crypto_pack32(z0, z1); +} + +static void octeon_snow3g_start(MIPSOcteonCryptoState *crypto, uint64_t data) +{ + int i; + + for (i = 0; i < 14; i++) { + octeon_snow3g_set_lfsr(crypto, i, octeon_snow3g_lfsr(crypto, i)); + } + octeon_snow3g_set_lfsr(crypto, 14, data >> 32); + octeon_snow3g_set_lfsr(crypto, 15, data); + for (i = 0; i < 3; i++) { + octeon_snow3g_set_fsm(crypto, i, 0); + } + + for (i = 0; i < 32; i++) { + uint32_t f = octeon_snow3g_clock_fsm(crypto); + + octeon_snow3g_clock_lfsr(crypto, true, f); + } + + (void)octeon_snow3g_clock_fsm(crypto); + octeon_snow3g_clock_lfsr(crypto, false, 0); + octeon_snow3g_queue_result(crypto); +} + +static void octeon_snow3g_more(MIPSOcteonCryptoState *crypto) +{ + octeon_snow3g_queue_result(crypto); +} + +void helper_octeon_cp2_mt_snow3g_start(CPUMIPSState *env, uint64_t value) +{ + octeon_snow3g_start(&env->octeon_crypto, value); +} + +void helper_octeon_cp2_mt_snow3g_more(CPUMIPSState *env, uint64_t value) +{ + (void)value; + octeon_snow3g_more(&env->octeon_crypto); +} + void helper_octeon_cp2_mt_zuc_start(CPUMIPSState *env, uint64_t value) { octeon_zuc_start(&env->octeon_crypto, value); From 9bf93903f715d1188d0a9640f727ffe554fc5b7d Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Mon, 8 Jun 2026 12:59:33 -0600 Subject: [PATCH 08/23] target/mips: add Octeon AES COP2 helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Message-ID: <20260608-mips-octeon-missing-insns-v2-v16-8-daef7a0d8b04@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- target/mips/helper.h | 4 + target/mips/tcg/octeon_crypto.c | 145 ++++++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+) 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); From e94d1a2fe0d9517c90a3903de9ec909e167b4aff Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Mon, 8 Jun 2026 12:59:34 -0600 Subject: [PATCH 09/23] target/mips: add Octeon SMS4 COP2 helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add helper support for the Octeon SMS4 operation selectors. SMS4 reuses the AES RESINP, IV, and key banks, so the helpers share the existing AES state while implementing the SMS4 ECB/CBC encrypt and decrypt operations. Signed-off-by: James Hilliard Message-ID: <20260608-mips-octeon-missing-insns-v2-v16-9-daef7a0d8b04@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- target/mips/helper.h | 4 ++ target/mips/tcg/octeon_crypto.c | 123 ++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) diff --git a/target/mips/helper.h b/target/mips/helper.h index 39c226ded9..4949b94657 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -56,6 +56,10 @@ 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) +DEF_HELPER_2(octeon_cp2_mt_sms4_enc_cbc1, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_sms4_enc1, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_sms4_dec_cbc1, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_sms4_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 117e3a5026..bcffd17ab6 100644 --- a/target/mips/tcg/octeon_crypto.c +++ b/target/mips/tcg/octeon_crypto.c @@ -985,6 +985,129 @@ void helper_octeon_cp2_mt_aes_dec1(CPUMIPSState *env, uint64_t value) octeon_aes_decrypt_common(crypto, false); } +static uint32_t octeon_sms4_t(uint32_t x) +{ + x = sm4_subword(x); + return x ^ rol32(x, 2) ^ rol32(x, 10) ^ rol32(x, 18) ^ rol32(x, 24); +} + +static uint32_t octeon_sms4_t_key(uint32_t x) +{ + x = sm4_subword(x); + return x ^ rol32(x, 13) ^ rol32(x, 23); +} + +static void octeon_sms4_expand_key(const uint8_t *key, uint32_t round_keys[32]) +{ + static const uint32_t fk[4] = { + 0xa3b1bac6U, 0x56aa3350U, 0x677d9197U, 0xb27022dcU, + }; + uint32_t k[36]; + + for (int i = 0; i < 4; i++) { + k[i] = ldl_be_p(key + i * 4) ^ fk[i]; + } + for (int i = 0; i < 32; i++) { + k[i + 4] = k[i] ^ octeon_sms4_t_key(k[i + 1] ^ k[i + 2] ^ + k[i + 3] ^ sm4_ck[i]); + round_keys[i] = k[i + 4]; + } +} + +static void octeon_sms4_crypt_block(const uint8_t *in, uint8_t *out, + const uint32_t round_keys[32], + bool encrypt) +{ + uint32_t x[36]; + + for (int i = 0; i < 4; i++) { + x[i] = ldl_be_p(in + i * 4); + } + for (int i = 0; i < 32; i++) { + uint32_t rk = round_keys[encrypt ? i : 31 - i]; + + x[i + 4] = x[i] ^ octeon_sms4_t(x[i + 1] ^ x[i + 2] ^ + x[i + 3] ^ rk); + } + stl_be_p(out, x[35]); + stl_be_p(out + 4, x[34]); + stl_be_p(out + 8, x[33]); + stl_be_p(out + 12, x[32]); +} + +static void octeon_sms4_crypt_common(MIPSOcteonCryptoState *crypto, + bool encrypt, bool cbc) +{ + uint8_t key[16]; + uint8_t in[16]; + uint8_t out[16]; + uint8_t iv[16]; + uint8_t next_iv[16]; + uint32_t round_keys[32]; + + /* + * SMS4 aliases the AES state onto the RESINP, IV, and KEY banks, + * with only the operation selectors remaining distinct. + */ + octeon_aes_load_key(crypto, key, sizeof(key)); + octeon_aes_load_block(crypto->aes_resinp, in); + if (cbc) { + octeon_aes_load_block(crypto->aes_iv, iv); + if (encrypt) { + for (int i = 0; i < sizeof(in); i++) { + in[i] ^= iv[i]; + } + } else { + memcpy(next_iv, in, sizeof(next_iv)); + } + } + + octeon_sms4_expand_key(key, round_keys); + octeon_sms4_crypt_block(in, out, round_keys, encrypt); + if (cbc && !encrypt) { + for (int 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, encrypt ? out : next_iv); + } +} + +void helper_octeon_cp2_mt_sms4_enc_cbc1(CPUMIPSState *env, uint64_t value) +{ + MIPSOcteonCryptoState *crypto = &env->octeon_crypto; + + crypto->aes_resinp[1] = value; + octeon_sms4_crypt_common(crypto, true, true); +} + +void helper_octeon_cp2_mt_sms4_enc1(CPUMIPSState *env, uint64_t value) +{ + MIPSOcteonCryptoState *crypto = &env->octeon_crypto; + + crypto->aes_resinp[1] = value; + octeon_sms4_crypt_common(crypto, true, false); +} + +void helper_octeon_cp2_mt_sms4_dec_cbc1(CPUMIPSState *env, uint64_t value) +{ + MIPSOcteonCryptoState *crypto = &env->octeon_crypto; + + crypto->aes_resinp[1] = value; + octeon_sms4_crypt_common(crypto, false, true); +} + +void helper_octeon_cp2_mt_sms4_dec1(CPUMIPSState *env, uint64_t value) +{ + MIPSOcteonCryptoState *crypto = &env->octeon_crypto; + + crypto->aes_resinp[1] = value; + octeon_sms4_crypt_common(crypto, false, false); +} + void helper_octeon_cp2_mt_snow3g_start(CPUMIPSState *env, uint64_t value) { octeon_snow3g_start(&env->octeon_crypto, value); From ff155dd718c6dfb156710dc0ab0f72a948c83ed0 Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Mon, 8 Jun 2026 12:59:35 -0600 Subject: [PATCH 10/23] target/mips: add Octeon 3DES and KASUMI COP2 helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add helper support for the Octeon 3DES and KASUMI operation selectors. The 3DES helpers implement ECB and CBC encrypt/decrypt over the shared 3DES key, IV, and result bank. KASUMI reuses the same register bank and adds its own encrypt selectors. Only the operation selectors require helper code. Simple key, IV, and result register transfers are handled by direct selector decode. Signed-off-by: James Hilliard Message-ID: <20260608-mips-octeon-missing-insns-v2-v16-10-daef7a0d8b04@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- target/mips/helper.h | 6 + target/mips/tcg/octeon_crypto.c | 458 ++++++++++++++++++++++++++++++++ 2 files changed, 464 insertions(+) diff --git a/target/mips/helper.h b/target/mips/helper.h index 4949b94657..c9332c5c52 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -60,6 +60,12 @@ DEF_HELPER_2(octeon_cp2_mt_sms4_enc_cbc1, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_sms4_enc1, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_sms4_dec_cbc1, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_sms4_dec1, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_des3_enc_cbc, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_kas_enc_cbc, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_des3_enc, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_kas_enc, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_des3_dec_cbc, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_des3_dec, 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 bcffd17ab6..8ea79e3756 100644 --- a/target/mips/tcg/octeon_crypto.c +++ b/target/mips/tcg/octeon_crypto.c @@ -1108,6 +1108,464 @@ void helper_octeon_cp2_mt_sms4_dec1(CPUMIPSState *env, uint64_t value) octeon_sms4_crypt_common(crypto, false, false); } +static const uint8_t octeon_des_ip[64] = { + 58, 50, 42, 34, 26, 18, 10, 2, + 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, + 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7, +}; + +static const uint8_t octeon_des_fp[64] = { + 40, 8, 48, 16, 56, 24, 64, 32, + 39, 7, 47, 15, 55, 23, 63, 31, + 38, 6, 46, 14, 54, 22, 62, 30, + 37, 5, 45, 13, 53, 21, 61, 29, + 36, 4, 44, 12, 52, 20, 60, 28, + 35, 3, 43, 11, 51, 19, 59, 27, + 34, 2, 42, 10, 50, 18, 58, 26, + 33, 1, 41, 9, 49, 17, 57, 25, +}; + +static const uint8_t octeon_des_e[48] = { + 32, 1, 2, 3, 4, 5, + 4, 5, 6, 7, 8, 9, + 8, 9, 10, 11, 12, 13, + 12, 13, 14, 15, 16, 17, + 16, 17, 18, 19, 20, 21, + 20, 21, 22, 23, 24, 25, + 24, 25, 26, 27, 28, 29, + 28, 29, 30, 31, 32, 1, +}; + +static const uint8_t octeon_des_p[32] = { + 16, 7, 20, 21, 29, 12, 28, 17, + 1, 15, 23, 26, 5, 18, 31, 10, + 2, 8, 24, 14, 32, 27, 3, 9, + 19, 13, 30, 6, 22, 11, 4, 25, +}; + +static const uint8_t octeon_des_pc1[56] = { + 57, 49, 41, 33, 25, 17, 9, + 1, 58, 50, 42, 34, 26, 18, + 10, 2, 59, 51, 43, 35, 27, + 19, 11, 3, 60, 52, 44, 36, + 63, 55, 47, 39, 31, 23, 15, + 7, 62, 54, 46, 38, 30, 22, + 14, 6, 61, 53, 45, 37, 29, + 21, 13, 5, 28, 20, 12, 4, +}; + +static const uint8_t octeon_des_pc2[48] = { + 14, 17, 11, 24, 1, 5, + 3, 28, 15, 6, 21, 10, + 23, 19, 12, 4, 26, 8, + 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, + 30, 40, 51, 45, 33, 48, + 44, 49, 39, 56, 34, 53, + 46, 42, 50, 36, 29, 32, +}; + +static const uint8_t octeon_des_rotations[16] = { + 1, 1, 2, 2, 2, 2, 2, 2, + 1, 2, 2, 2, 2, 2, 2, 1, +}; + +static const uint8_t octeon_des_sboxes[8][64] = { + { + 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, + 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, + 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, + 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13, + }, + { + 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, + 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, + 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, + 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9, + }, + { + 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, + 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, + 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, + 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12, + }, + { + 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, + 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, + 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, + 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14, + }, + { + 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, + 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, + 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, + 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3, + }, + { + 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, + 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, + 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, + 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13, + }, + { + 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, + 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, + 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, + 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12, + }, + { + 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, + 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, + 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, + 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11, + }, +}; + +static const uint8_t octeon_kasumi_s7[128] = { + 54, 50, 62, 56, 22, 34, 94, 96, 38, 6, 63, 93, 2, 18, + 123, 33, 55, 113, 39, 114, 21, 67, 65, 12, 47, 73, 46, 27, + 25, 111, 124, 81, 53, 9, 121, 79, 52, 60, 58, 48, 101, 127, + 40, 120, 104, 70, 71, 43, 20, 122, 72, 61, 23, 109, 13, 100, + 77, 1, 16, 7, 82, 10, 105, 98, 117, 116, 76, 11, 89, 106, + 0, 125, 118, 99, 86, 69, 30, 57, 126, 87, 112, 51, 17, 5, + 95, 14, 90, 84, 91, 8, 35, 103, 32, 97, 28, 66, 102, 31, + 26, 45, 75, 4, 85, 92, 37, 74, 80, 49, 68, 29, 115, 44, + 64, 107, 108, 24, 110, 83, 36, 78, 42, 19, 15, 41, 88, 119, + 59, 3, +}; + +static const uint16_t octeon_kasumi_s9[512] = { + 167, 239, 161, 379, 391, 334, 9, 338, 38, 226, 48, 358, 452, 385, + 90, 397, 183, 253, 147, 331, 415, 340, 51, 362, 306, 500, 262, 82, + 216, 159, 356, 177, 175, 241, 489, 37, 206, 17, 0, 333, 44, 254, + 378, 58, 143, 220, 81, 400, 95, 3, 315, 245, 54, 235, 218, 405, + 472, 264, 172, 494, 371, 290, 399, 76, 165, 197, 395, 121, 257, 480, + 423, 212, 240, 28, 462, 176, 406, 507, 288, 223, 501, 407, 249, 265, + 89, 186, 221, 428, 164, 74, 440, 196, 458, 421, 350, 163, 232, 158, + 134, 354, 13, 250, 491, 142, 191, 69, 193, 425, 152, 227, 366, 135, + 344, 300, 276, 242, 437, 320, 113, 278, 11, 243, 87, 317, 36, 93, + 496, 27, 487, 446, 482, 41, 68, 156, 457, 131, 326, 403, 339, 20, + 39, 115, 442, 124, 475, 384, 508, 53, 112, 170, 479, 151, 126, 169, + 73, 268, 279, 321, 168, 364, 363, 292, 46, 499, 393, 327, 324, 24, + 456, 267, 157, 460, 488, 426, 309, 229, 439, 506, 208, 271, 349, 401, + 434, 236, 16, 209, 359, 52, 56, 120, 199, 277, 465, 416, 252, 287, + 246, 6, 83, 305, 420, 345, 153, 502, 65, 61, 244, 282, 173, 222, + 418, 67, 386, 368, 261, 101, 476, 291, 195, 430, 49, 79, 166, 330, + 280, 383, 373, 128, 382, 408, 155, 495, 367, 388, 274, 107, 459, 417, + 62, 454, 132, 225, 203, 316, 234, 14, 301, 91, 503, 286, 424, 211, + 347, 307, 140, 374, 35, 103, 125, 427, 19, 214, 453, 146, 498, 314, + 444, 230, 256, 329, 198, 285, 50, 116, 78, 410, 10, 205, 510, 171, + 231, 45, 139, 467, 29, 86, 505, 32, 72, 26, 342, 150, 313, 490, + 431, 238, 411, 325, 149, 473, 40, 119, 174, 355, 185, 233, 389, 71, + 448, 273, 372, 55, 110, 178, 322, 12, 469, 392, 369, 190, 1, 109, + 375, 137, 181, 88, 75, 308, 260, 484, 98, 272, 370, 275, 412, 111, + 336, 318, 4, 504, 492, 259, 304, 77, 337, 435, 21, 357, 303, 332, + 483, 18, 47, 85, 25, 497, 474, 289, 100, 269, 296, 478, 270, 106, + 31, 104, 433, 84, 414, 486, 394, 96, 99, 154, 511, 148, 413, 361, + 409, 255, 162, 215, 302, 201, 266, 351, 343, 144, 441, 365, 108, 298, + 251, 34, 182, 509, 138, 210, 335, 133, 311, 352, 328, 141, 396, 346, + 123, 319, 450, 281, 429, 228, 443, 481, 92, 404, 485, 422, 248, 297, + 23, 213, 130, 466, 22, 217, 283, 70, 294, 360, 419, 127, 312, 377, + 7, 468, 194, 2, 117, 295, 463, 258, 224, 447, 247, 187, 80, 398, + 284, 353, 105, 390, 299, 471, 470, 184, 57, 200, 348, 63, 204, 188, + 33, 451, 97, 30, 310, 219, 94, 160, 129, 493, 64, 179, 263, 102, + 189, 207, 114, 402, 438, 477, 387, 122, 192, 42, 381, 5, 145, 118, + 180, 449, 293, 323, 136, 380, 43, 66, 60, 455, 341, 445, 202, 432, + 8, 237, 15, 376, 436, 464, 59, 461, +}; + +static const uint16_t octeon_kasumi_constants[8] = { + 0x0123, 0x4567, 0x89ab, 0xcdef, 0xfedc, 0xba98, 0x7654, 0x3210, +}; + +typedef struct OcteonKasumiSubkeys { + uint16_t kli1[8]; + uint16_t kli2[8]; + uint16_t koi1[8]; + uint16_t koi2[8]; + uint16_t koi3[8]; + uint16_t kii1[8]; + uint16_t kii2[8]; + uint16_t kii3[8]; +} OcteonKasumiSubkeys; + +static uint64_t octeon_des_permute(uint64_t input, const uint8_t *table, + size_t output_bits, size_t input_bits) +{ + uint64_t out = 0; + + for (size_t i = 0; i < output_bits; i++) { + unsigned src = table[i] - 1; + + out = (out << 1) | ((input >> (input_bits - 1 - src)) & 1); + } + return out; +} + +static uint32_t octeon_des_rotate28(uint32_t v, unsigned shift) +{ + return ((v << shift) | (v >> (28 - shift))) & 0x0fffffffU; +} + +static void octeon_des_expand_subkeys(uint64_t key, uint64_t subkeys[16]) +{ + uint64_t permuted = octeon_des_permute(key, octeon_des_pc1, + ARRAY_SIZE(octeon_des_pc1), 64); + uint32_t c = (permuted >> 28) & 0x0fffffffU; + uint32_t d = permuted & 0x0fffffffU; + + for (int i = 0; i < 16; i++) { + c = octeon_des_rotate28(c, octeon_des_rotations[i]); + d = octeon_des_rotate28(d, octeon_des_rotations[i]); + subkeys[i] = octeon_des_permute(((uint64_t)c << 28) | d, + octeon_des_pc2, + ARRAY_SIZE(octeon_des_pc2), 56); + } +} + +static uint32_t octeon_des_f(uint32_t r, uint64_t subkey) +{ + uint64_t expanded = octeon_des_permute(r, octeon_des_e, + ARRAY_SIZE(octeon_des_e), 32); + uint32_t out = 0; + + expanded ^= subkey; + for (int i = 0; i < 8; i++) { + uint8_t sextet = (expanded >> (42 - i * 6)) & 0x3f; + uint8_t row = ((sextet & 0x20) >> 4) | (sextet & 0x01); + uint8_t col = (sextet >> 1) & 0x0f; + + out = (out << 4) | octeon_des_sboxes[i][row * 16 + col]; + } + + return octeon_des_permute(out, octeon_des_p, ARRAY_SIZE(octeon_des_p), 32); +} + +static uint64_t octeon_des_block_crypt(uint64_t block, uint64_t key, + bool encrypt) +{ + uint64_t subkeys[16]; + uint64_t permuted = octeon_des_permute(block, octeon_des_ip, + ARRAY_SIZE(octeon_des_ip), 64); + uint32_t l = permuted >> 32; + uint32_t r = permuted; + + octeon_des_expand_subkeys(key, subkeys); + + for (int i = 0; i < 16; i++) { + uint32_t next = l ^ octeon_des_f(r, subkeys[encrypt ? i : 15 - i]); + + l = r; + r = next; + } + + return octeon_des_permute(((uint64_t)r << 32) | l, + octeon_des_fp, ARRAY_SIZE(octeon_des_fp), 64); +} + +static uint64_t octeon_3des_block_crypt(uint64_t block, const uint64_t keys[3], + bool encrypt) +{ + if (encrypt) { + block = octeon_des_block_crypt(block, keys[0], true); + block = octeon_des_block_crypt(block, keys[1], false); + block = octeon_des_block_crypt(block, keys[2], true); + } else { + block = octeon_des_block_crypt(block, keys[2], false); + block = octeon_des_block_crypt(block, keys[1], true); + block = octeon_des_block_crypt(block, keys[0], false); + } + return block; +} + +static void octeon_3des_crypt_common(MIPSOcteonCryptoState *crypto, + uint64_t input_reg, + bool encrypt, bool cbc) +{ + const uint64_t keys[3] = { + crypto->des3_key[0], + crypto->des3_key[1], + crypto->des3_key[2], + }; + uint64_t block = input_reg; + + if (cbc) { + if (encrypt) { + block ^= crypto->des3_iv; + block = octeon_3des_block_crypt(block, keys, true); + crypto->des3_iv = block; + } else { + block = octeon_3des_block_crypt(block, keys, false); + block ^= crypto->des3_iv; + crypto->des3_iv = input_reg; + } + } else { + block = octeon_3des_block_crypt(block, keys, encrypt); + } + + crypto->des3_result = block; +} + +static uint16_t octeon_rol16(uint16_t value, unsigned int bits) +{ + return (value << bits) | (value >> (16 - bits)); +} + +static void octeon_kasumi_key_schedule(const uint64_t key_regs[2], + OcteonKasumiSubkeys *subkeys) +{ + uint16_t key[8]; + uint16_t key_prime[8]; + + key[0] = key_regs[0] >> 48; + key[1] = key_regs[0] >> 32; + key[2] = key_regs[0] >> 16; + key[3] = key_regs[0]; + key[4] = key_regs[1] >> 48; + key[5] = key_regs[1] >> 32; + key[6] = key_regs[1] >> 16; + key[7] = key_regs[1]; + + for (int i = 0; i < 8; i++) { + key_prime[i] = key[i] ^ octeon_kasumi_constants[i]; + } + + for (int i = 0; i < 8; i++) { + subkeys->kli1[i] = octeon_rol16(key[i], 1); + subkeys->kli2[i] = key_prime[(i + 2) & 7]; + subkeys->koi1[i] = octeon_rol16(key[(i + 1) & 7], 5); + subkeys->koi2[i] = octeon_rol16(key[(i + 5) & 7], 8); + subkeys->koi3[i] = octeon_rol16(key[(i + 6) & 7], 13); + subkeys->kii1[i] = key_prime[(i + 4) & 7]; + subkeys->kii2[i] = key_prime[(i + 3) & 7]; + subkeys->kii3[i] = key_prime[(i + 7) & 7]; + } +} + +static uint16_t octeon_kasumi_fi(uint16_t in, uint16_t subkey) +{ + uint16_t nine = in >> 7; + uint16_t seven = in & 0x7f; + + nine = octeon_kasumi_s9[nine] ^ seven; + seven = octeon_kasumi_s7[seven] ^ (nine & 0x7f); + seven ^= subkey >> 9; + nine ^= subkey & 0x1ff; + nine = octeon_kasumi_s9[nine] ^ seven; + seven = octeon_kasumi_s7[seven] ^ (nine & 0x7f); + return (seven << 9) | nine; +} + +static uint32_t octeon_kasumi_fo(uint32_t in, int index, + const OcteonKasumiSubkeys *subkeys) +{ + uint16_t left = in >> 16; + uint16_t right = in; + + left ^= subkeys->koi1[index]; + left = octeon_kasumi_fi(left, subkeys->kii1[index]); + left ^= right; + right ^= subkeys->koi2[index]; + right = octeon_kasumi_fi(right, subkeys->kii2[index]); + right ^= left; + left ^= subkeys->koi3[index]; + left = octeon_kasumi_fi(left, subkeys->kii3[index]); + left ^= right; + + return ((uint32_t)right << 16) | left; +} + +static uint32_t octeon_kasumi_fl(uint32_t in, int index, + const OcteonKasumiSubkeys *subkeys) +{ + uint16_t left = in >> 16; + uint16_t right = in; + uint16_t a = left & subkeys->kli1[index]; + uint16_t b; + + right ^= octeon_rol16(a, 1); + b = right | subkeys->kli2[index]; + left ^= octeon_rol16(b, 1); + return ((uint32_t)left << 16) | right; +} + +static uint64_t octeon_kasumi_block_encrypt(uint64_t block, + const uint64_t key_regs[2]) +{ + OcteonKasumiSubkeys subkeys; + uint32_t left = block >> 32; + uint32_t right = block; + + octeon_kasumi_key_schedule(key_regs, &subkeys); + + for (int i = 0; i < 8; ) { + uint32_t temp = octeon_kasumi_fl(left, i, &subkeys); + + temp = octeon_kasumi_fo(temp, i++, &subkeys); + right ^= temp; + temp = octeon_kasumi_fo(right, i, &subkeys); + temp = octeon_kasumi_fl(temp, i++, &subkeys); + left ^= temp; + } + + return ((uint64_t)left << 32) | right; +} + +static void octeon_kasumi_crypt_common(MIPSOcteonCryptoState *crypto, + uint64_t input_reg, bool cbc) +{ + const uint64_t key_regs[2] = { + crypto->des3_key[0], + crypto->des3_key[1], + }; + uint64_t block = input_reg; + + if (cbc) { + block ^= crypto->des3_iv; + } + + block = octeon_kasumi_block_encrypt(block, key_regs); + if (cbc) { + crypto->des3_iv = block; + } + crypto->des3_result = block; +} + +void helper_octeon_cp2_mt_des3_enc_cbc(CPUMIPSState *env, uint64_t value) +{ + octeon_3des_crypt_common(&env->octeon_crypto, value, true, true); +} + +void helper_octeon_cp2_mt_kas_enc_cbc(CPUMIPSState *env, uint64_t value) +{ + octeon_kasumi_crypt_common(&env->octeon_crypto, value, true); +} + +void helper_octeon_cp2_mt_des3_enc(CPUMIPSState *env, uint64_t value) +{ + octeon_3des_crypt_common(&env->octeon_crypto, value, true, false); +} + +void helper_octeon_cp2_mt_kas_enc(CPUMIPSState *env, uint64_t value) +{ + octeon_kasumi_crypt_common(&env->octeon_crypto, value, false); +} + +void helper_octeon_cp2_mt_des3_dec_cbc(CPUMIPSState *env, uint64_t value) +{ + octeon_3des_crypt_common(&env->octeon_crypto, value, false, true); +} + +void helper_octeon_cp2_mt_des3_dec(CPUMIPSState *env, uint64_t value) +{ + octeon_3des_crypt_common(&env->octeon_crypto, value, false, false); +} + void helper_octeon_cp2_mt_snow3g_start(CPUMIPSState *env, uint64_t value) { octeon_snow3g_start(&env->octeon_crypto, value); From c75e3503c814802a23785fce0df9258b2b83f3cb Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Mon, 8 Jun 2026 12:59:36 -0600 Subject: [PATCH 11/23] target/mips: add Octeon Camellia COP2 helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add helper support for the Octeon Camellia ROUND, FL, and FLINV selectors. The engine reuses the AES RESINP bank, and guest-managed key schedules drive the Camellia F-function and FL layers through these COP2 operations. Implement the Camellia F-function and FL layers directly from RFC 3713. Signed-off-by: James Hilliard Message-ID: <20260608-mips-octeon-missing-insns-v2-v16-11-daef7a0d8b04@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- target/mips/helper.h | 3 + target/mips/tcg/octeon_crypto.c | 126 ++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) diff --git a/target/mips/helper.h b/target/mips/helper.h index c9332c5c52..71b7a2b30e 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -66,6 +66,9 @@ DEF_HELPER_2(octeon_cp2_mt_des3_enc, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_kas_enc, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_des3_dec_cbc, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_des3_dec, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_camellia_fl, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_camellia_flinv, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_camellia_round, 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 8ea79e3756..430feaf5f4 100644 --- a/target/mips/tcg/octeon_crypto.c +++ b/target/mips/tcg/octeon_crypto.c @@ -1566,6 +1566,132 @@ void helper_octeon_cp2_mt_des3_dec(CPUMIPSState *env, uint64_t value) octeon_3des_crypt_common(&env->octeon_crypto, value, false, false); } +static const uint8_t camellia_sbox1[256] = { + 112, 130, 44, 236, 179, 39, 192, 229, 228, 133, 87, 53, 234, 12, + 174, 65, 35, 239, 107, 147, 69, 25, 165, 33, 237, 14, 79, 78, + 29, 101, 146, 189, 134, 184, 175, 143, 124, 235, 31, 206, 62, 48, + 220, 95, 94, 197, 11, 26, 166, 225, 57, 202, 213, 71, 93, 61, + 217, 1, 90, 214, 81, 86, 108, 77, 139, 13, 154, 102, 251, 204, + 176, 45, 116, 18, 43, 32, 240, 177, 132, 153, 223, 76, 203, 194, + 52, 126, 118, 5, 109, 183, 169, 49, 209, 23, 4, 215, 20, 88, + 58, 97, 222, 27, 17, 28, 50, 15, 156, 22, 83, 24, 242, 34, + 254, 68, 207, 178, 195, 181, 122, 145, 36, 8, 232, 168, 96, 252, + 105, 80, 170, 208, 160, 125, 161, 137, 98, 151, 84, 91, 30, 149, + 224, 255, 100, 210, 16, 196, 0, 72, 163, 247, 117, 219, 138, 3, + 230, 218, 9, 63, 221, 148, 135, 92, 131, 2, 205, 74, 144, 51, + 115, 103, 246, 243, 157, 127, 191, 226, 82, 155, 216, 38, 200, 55, + 198, 59, 129, 150, 111, 75, 19, 190, 99, 46, 233, 121, 167, 140, + 159, 110, 188, 142, 41, 245, 249, 182, 47, 253, 180, 89, 120, 152, + 6, 106, 231, 70, 113, 186, 212, 37, 171, 66, 136, 162, 141, 250, + 114, 7, 185, 85, 248, 238, 172, 10, 54, 73, 42, 104, 60, 56, + 241, 164, 64, 40, 211, 123, 187, 201, 67, 193, 21, 227, 173, 244, + 119, 199, 128, 158, +}; + +static uint8_t camellia_rotl8(uint8_t v, unsigned int shift) +{ + return (v << shift) | (v >> (8 - shift)); +} + +static uint8_t camellia_sbox2(uint8_t x) +{ + return camellia_rotl8(camellia_sbox1[x], 1); +} + +static uint8_t camellia_sbox3(uint8_t x) +{ + return camellia_rotl8(camellia_sbox1[x], 7); +} + +static uint8_t camellia_sbox4(uint8_t x) +{ + return camellia_sbox1[camellia_rotl8(x, 1)]; +} + +static uint64_t camellia_f(uint64_t input, uint64_t key) +{ + uint64_t x = input ^ key; + uint8_t t1 = camellia_sbox1[x >> 56]; + uint8_t t2 = camellia_sbox2((x >> 48) & 0xff); + uint8_t t3 = camellia_sbox3((x >> 40) & 0xff); + uint8_t t4 = camellia_sbox4((x >> 32) & 0xff); + uint8_t t5 = camellia_sbox2((x >> 24) & 0xff); + uint8_t t6 = camellia_sbox3((x >> 16) & 0xff); + uint8_t t7 = camellia_sbox4((x >> 8) & 0xff); + uint8_t t8 = camellia_sbox1[x & 0xff]; + uint8_t y1 = t1 ^ t3 ^ t4 ^ t6 ^ t7 ^ t8; + uint8_t y2 = t1 ^ t2 ^ t4 ^ t5 ^ t7 ^ t8; + uint8_t y3 = t1 ^ t2 ^ t3 ^ t5 ^ t6 ^ t8; + uint8_t y4 = t2 ^ t3 ^ t4 ^ t5 ^ t6 ^ t7; + uint8_t y5 = t1 ^ t2 ^ t6 ^ t7 ^ t8; + uint8_t y6 = t2 ^ t3 ^ t5 ^ t7 ^ t8; + uint8_t y7 = t3 ^ t4 ^ t5 ^ t6 ^ t8; + uint8_t y8 = t1 ^ t4 ^ t5 ^ t6 ^ t7; + + return ((uint64_t)y1 << 56) | ((uint64_t)y2 << 48) | + ((uint64_t)y3 << 40) | ((uint64_t)y4 << 32) | + ((uint64_t)y5 << 24) | ((uint64_t)y6 << 16) | + ((uint64_t)y7 << 8) | y8; +} + +static uint64_t camellia_fl(uint64_t input, uint64_t key) +{ + uint32_t x1 = input >> 32; + uint32_t x2 = input; + uint32_t k1 = key >> 32; + uint32_t k2 = key; + + x2 ^= rol32(x1 & k1, 1); + x1 ^= x2 | k2; + return ((uint64_t)x1 << 32) | x2; +} + +static uint64_t camellia_flinv(uint64_t input, uint64_t key) +{ + uint32_t y1 = input >> 32; + uint32_t y2 = input; + uint32_t k1 = key >> 32; + uint32_t k2 = key; + + y1 ^= y2 | k2; + y2 ^= rol32(y1 & k1, 1); + return ((uint64_t)y1 << 32) | y2; +} + +static void octeon_camellia_round(MIPSOcteonCryptoState *crypto, uint64_t key) +{ + uint64_t left = crypto->aes_resinp[0]; + uint64_t right = crypto->aes_resinp[1]; + + crypto->aes_resinp[0] = right ^ camellia_f(left, key); + crypto->aes_resinp[1] = left; +} + +static void octeon_camellia_fl_layer(MIPSOcteonCryptoState *crypto, + uint64_t key, bool inverse) +{ + uint64_t state = crypto->aes_resinp[inverse ? 1 : 0]; + + crypto->aes_resinp[inverse ? 1 : 0] = inverse ? + camellia_flinv(state, key) : + camellia_fl(state, key); +} + +void helper_octeon_cp2_mt_camellia_fl(CPUMIPSState *env, uint64_t value) +{ + octeon_camellia_fl_layer(&env->octeon_crypto, value, false); +} + +void helper_octeon_cp2_mt_camellia_flinv(CPUMIPSState *env, uint64_t value) +{ + octeon_camellia_fl_layer(&env->octeon_crypto, value, true); +} + +void helper_octeon_cp2_mt_camellia_round(CPUMIPSState *env, uint64_t value) +{ + octeon_camellia_round(&env->octeon_crypto, value); +} + void helper_octeon_cp2_mt_snow3g_start(CPUMIPSState *env, uint64_t value) { octeon_snow3g_start(&env->octeon_crypto, value); From 900c423717ddb062b89954f533c174760705b8d7 Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Mon, 8 Jun 2026 12:59:37 -0600 Subject: [PATCH 12/23] target/mips: add Octeon HSH COP2 helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add helper support for the Octeon HSH hash selectors. This includes the base HSH data/IV windows, MD5, SHA1, SHA256, and SHA512 transform paths, and the shared HSH/SHA512 register-window readback and write operations. The SHA512 path shares the wide HSH register bank with SHA3, SNOW3G, and ZUC. Keep the aliased readback and write paths centralized so selector decode can route register accesses through these helpers when side effects are required. Signed-off-by: James Hilliard Message-ID: <20260608-mips-octeon-missing-insns-v2-v16-12-daef7a0d8b04@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- target/mips/helper.h | 5 + target/mips/tcg/octeon_crypto.c | 373 ++++++++++++++++++++++++++++++++ 2 files changed, 378 insertions(+) diff --git a/target/mips/helper.h b/target/mips/helper.h index 71b7a2b30e..834f2d0769 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -69,6 +69,11 @@ DEF_HELPER_2(octeon_cp2_mt_des3_dec, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_camellia_fl, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_camellia_flinv, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_camellia_round, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_hsh_startsha1_compat, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_hsh_startmd5, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_hsh_startsha256, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_hsh_startsha, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_hsh_startsha512, 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 430feaf5f4..82ad355d56 100644 --- a/target/mips/tcg/octeon_crypto.c +++ b/target/mips/tcg/octeon_crypto.c @@ -153,6 +153,346 @@ static void octeon_gfm_mul64_uia2(const uint64_t x[2], const uint64_t y[2], out[1] = revbit64(res); } +static uint32_t octeon_hsh_get32(const uint64_t *regs, unsigned int index) +{ + return regs[index]; +} + +static void octeon_hsh_set32(uint64_t *regs, unsigned int index, uint32_t value) +{ + regs[index] = (regs[index] & ~(uint64_t)UINT32_MAX) | value; +} + +static void octeon_hsh_set_pair(uint64_t *regs, unsigned int index, + uint64_t value) +{ + octeon_hsh_set32(regs, index * 2, value >> 32); + octeon_hsh_set32(regs, index * 2 + 1, value); +} + +static void octeon_md5_transform(MIPSOcteonCryptoState *crypto) +{ + static const uint32_t k[64] = { + 0xd76aa478U, 0xe8c7b756U, 0x242070dbU, 0xc1bdceeeU, + 0xf57c0fafU, 0x4787c62aU, 0xa8304613U, 0xfd469501U, + 0x698098d8U, 0x8b44f7afU, 0xffff5bb1U, 0x895cd7beU, + 0x6b901122U, 0xfd987193U, 0xa679438eU, 0x49b40821U, + 0xf61e2562U, 0xc040b340U, 0x265e5a51U, 0xe9b6c7aaU, + 0xd62f105dU, 0x02441453U, 0xd8a1e681U, 0xe7d3fbc8U, + 0x21e1cde6U, 0xc33707d6U, 0xf4d50d87U, 0x455a14edU, + 0xa9e3e905U, 0xfcefa3f8U, 0x676f02d9U, 0x8d2a4c8aU, + 0xfffa3942U, 0x8771f681U, 0x6d9d6122U, 0xfde5380cU, + 0xa4beea44U, 0x4bdecfa9U, 0xf6bb4b60U, 0xbebfbc70U, + 0x289b7ec6U, 0xeaa127faU, 0xd4ef3085U, 0x04881d05U, + 0xd9d4d039U, 0xe6db99e5U, 0x1fa27cf8U, 0xc4ac5665U, + 0xf4292244U, 0x432aff97U, 0xab9423a7U, 0xfc93a039U, + 0x655b59c3U, 0x8f0ccc92U, 0xffeff47dU, 0x85845dd1U, + 0x6fa87e4fU, 0xfe2ce6e0U, 0xa3014314U, 0x4e0811a1U, + 0xf7537e82U, 0xbd3af235U, 0x2ad7d2bbU, 0xeb86d391U, + }; + static const uint8_t s[64] = { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, + }; + uint32_t m[16]; + uint32_t a, b, c, d; + uint32_t aa, bb, cc, dd; + int i; + + for (i = 0; i < 16; i++) { + m[i] = bswap32(octeon_hsh_get32(crypto->hsh_dat, i)); + } + + a = bswap32(octeon_hsh_get32(crypto->hsh_iv, 0)); + b = bswap32(octeon_hsh_get32(crypto->hsh_iv, 1)); + c = bswap32(octeon_hsh_get32(crypto->hsh_iv, 2)); + d = bswap32(octeon_hsh_get32(crypto->hsh_iv, 3)); + aa = a; + bb = b; + cc = c; + dd = d; + + for (i = 0; i < 64; i++) { + uint32_t f, g, tmp; + + if (i < 16) { + f = (b & c) | ((~b) & d); + g = i; + } else if (i < 32) { + f = (d & b) | ((~d) & c); + g = (5 * i + 1) & 0xf; + } else if (i < 48) { + f = b ^ c ^ d; + g = (3 * i + 5) & 0xf; + } else { + f = c ^ (b | (~d)); + g = (7 * i) & 0xf; + } + + tmp = d; + d = c; + c = b; + b = b + rol32(a + f + k[i] + m[g], s[i]); + a = tmp; + } + + a += aa; + b += bb; + c += cc; + d += dd; + octeon_hsh_set32(crypto->hsh_iv, 0, bswap32(a)); + octeon_hsh_set32(crypto->hsh_iv, 1, bswap32(b)); + octeon_hsh_set32(crypto->hsh_iv, 2, bswap32(c)); + octeon_hsh_set32(crypto->hsh_iv, 3, bswap32(d)); +} + +static void octeon_sha1_transform(MIPSOcteonCryptoState *crypto) +{ + uint32_t w[80]; + uint32_t a, b, c, d, e; + uint32_t orig[5]; + int i; + + for (i = 0; i < 16; i++) { + w[i] = octeon_hsh_get32(crypto->hsh_dat, i); + } + for (i = 16; i < 80; i++) { + w[i] = rol32(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1); + } + + for (i = 0; i < 5; i++) { + orig[i] = octeon_hsh_get32(crypto->hsh_iv, i); + } + a = orig[0]; + b = orig[1]; + c = orig[2]; + d = orig[3]; + e = orig[4]; + + for (i = 0; i < 80; i++) { + uint32_t f, k, temp; + + if (i < 20) { + f = (b & c) | ((~b) & d); + k = 0x5a827999; + } else if (i < 40) { + f = b ^ c ^ d; + k = 0x6ed9eba1; + } else if (i < 60) { + f = (b & c) | (b & d) | (c & d); + k = 0x8f1bbcdc; + } else { + f = b ^ c ^ d; + k = 0xca62c1d6; + } + + temp = rol32(a, 5) + f + e + k + w[i]; + e = d; + d = c; + c = rol32(b, 30); + b = a; + a = temp; + } + + orig[0] += a; + orig[1] += b; + orig[2] += c; + orig[3] += d; + orig[4] += e; + for (i = 0; i < 5; i++) { + octeon_hsh_set32(crypto->hsh_iv, i, orig[i]); + } +} + +static void octeon_sha256_transform(MIPSOcteonCryptoState *crypto) +{ + static const uint32_t k[64] = { + 0x428a2f98U, 0x71374491U, 0xb5c0fbcfU, 0xe9b5dba5U, + 0x3956c25bU, 0x59f111f1U, 0x923f82a4U, 0xab1c5ed5U, + 0xd807aa98U, 0x12835b01U, 0x243185beU, 0x550c7dc3U, + 0x72be5d74U, 0x80deb1feU, 0x9bdc06a7U, 0xc19bf174U, + 0xe49b69c1U, 0xefbe4786U, 0x0fc19dc6U, 0x240ca1ccU, + 0x2de92c6fU, 0x4a7484aaU, 0x5cb0a9dcU, 0x76f988daU, + 0x983e5152U, 0xa831c66dU, 0xb00327c8U, 0xbf597fc7U, + 0xc6e00bf3U, 0xd5a79147U, 0x06ca6351U, 0x14292967U, + 0x27b70a85U, 0x2e1b2138U, 0x4d2c6dfcU, 0x53380d13U, + 0x650a7354U, 0x766a0abbU, 0x81c2c92eU, 0x92722c85U, + 0xa2bfe8a1U, 0xa81a664bU, 0xc24b8b70U, 0xc76c51a3U, + 0xd192e819U, 0xd6990624U, 0xf40e3585U, 0x106aa070U, + 0x19a4c116U, 0x1e376c08U, 0x2748774cU, 0x34b0bcb5U, + 0x391c0cb3U, 0x4ed8aa4aU, 0x5b9cca4fU, 0x682e6ff3U, + 0x748f82eeU, 0x78a5636fU, 0x84c87814U, 0x8cc70208U, + 0x90befffaU, 0xa4506cebU, 0xbef9a3f7U, 0xc67178f2U, + }; + uint32_t w[64]; + uint32_t a, b, c, d, e, f, g, h; + uint32_t orig[8]; + int i; + + for (i = 0; i < 16; i++) { + w[i] = octeon_hsh_get32(crypto->hsh_dat, i); + } + for (i = 16; i < 64; i++) { + uint32_t s0 = ror32(w[i - 15], 7) ^ + ror32(w[i - 15], 18) ^ + (w[i - 15] >> 3); + uint32_t s1 = ror32(w[i - 2], 17) ^ + ror32(w[i - 2], 19) ^ + (w[i - 2] >> 10); + w[i] = w[i - 16] + s0 + w[i - 7] + s1; + } + + for (i = 0; i < 8; i++) { + orig[i] = octeon_hsh_get32(crypto->hsh_iv, i); + } + a = orig[0]; + b = orig[1]; + c = orig[2]; + d = orig[3]; + e = orig[4]; + f = orig[5]; + g = orig[6]; + h = orig[7]; + + for (i = 0; i < 64; i++) { + uint32_t s1 = ror32(e, 6) ^ + ror32(e, 11) ^ + ror32(e, 25); + uint32_t ch = (e & f) ^ ((~e) & g); + uint32_t temp1 = h + s1 + ch + k[i] + w[i]; + uint32_t s0 = ror32(a, 2) ^ + ror32(a, 13) ^ + ror32(a, 22); + uint32_t maj = (a & b) ^ (a & c) ^ (b & c); + uint32_t temp2 = s0 + maj; + + h = g; + g = f; + f = e; + e = d + temp1; + d = c; + c = b; + b = a; + a = temp1 + temp2; + } + + orig[0] += a; + orig[1] += b; + orig[2] += c; + orig[3] += d; + orig[4] += e; + orig[5] += f; + orig[6] += g; + orig[7] += h; + for (i = 0; i < 8; i++) { + octeon_hsh_set32(crypto->hsh_iv, i, orig[i]); + } +} + +static void octeon_sha512_transform(MIPSOcteonCryptoState *crypto) +{ + static const uint64_t k[80] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, + 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, + 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, + 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, + 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, + 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, + 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, + 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, + 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, + 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, + 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, + 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, + 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, + 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, + 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, + 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, + 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, + 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, + 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, + 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, + 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, + 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, + 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, + 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, + 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL, + }; + uint64_t w[80]; + uint64_t a, b, c, d, e, f, g, h; + int i; + + for (i = 0; i < 16; i++) { + w[i] = crypto->hsh_dat[i]; + } + for (i = 16; i < 80; i++) { + uint64_t s0 = ror64(w[i - 15], 1) ^ + ror64(w[i - 15], 8) ^ + (w[i - 15] >> 7); + uint64_t s1 = ror64(w[i - 2], 19) ^ + ror64(w[i - 2], 61) ^ + (w[i - 2] >> 6); + w[i] = w[i - 16] + s0 + w[i - 7] + s1; + } + + a = crypto->hsh_iv[0]; + b = crypto->hsh_iv[1]; + c = crypto->hsh_iv[2]; + d = crypto->hsh_iv[3]; + e = crypto->hsh_iv[4]; + f = crypto->hsh_iv[5]; + g = crypto->hsh_iv[6]; + h = crypto->hsh_iv[7]; + + for (i = 0; i < 80; i++) { + uint64_t s0 = ror64(a, 28) ^ + ror64(a, 34) ^ + ror64(a, 39); + uint64_t s1 = ror64(e, 14) ^ + ror64(e, 18) ^ + ror64(e, 41); + uint64_t ch = (e & f) ^ ((~e) & g); + uint64_t maj = (a & b) ^ (a & c) ^ (b & c); + uint64_t temp1 = h + s1 + ch + k[i] + w[i]; + uint64_t temp2 = s0 + maj; + + h = g; + g = f; + f = e; + e = d + temp1; + d = c; + c = b; + b = a; + a = temp1 + temp2; + } + + crypto->hsh_iv[0] += a; + crypto->hsh_iv[1] += b; + crypto->hsh_iv[2] += c; + crypto->hsh_iv[3] += d; + crypto->hsh_iv[4] += e; + crypto->hsh_iv[5] += f; + crypto->hsh_iv[6] += g; + crypto->hsh_iv[7] += h; +} + static const uint64_t octeon_sha3_round_constants[24] = { 0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, @@ -1713,6 +2053,39 @@ void helper_octeon_cp2_mt_zuc_more(CPUMIPSState *env, uint64_t value) octeon_zuc_more(&env->octeon_crypto, value); } +void helper_octeon_cp2_mt_hsh_startsha1_compat(CPUMIPSState *env, + uint64_t value) +{ + octeon_hsh_set_pair(env->octeon_crypto.hsh_dat, 7, value); + octeon_sha1_transform(&env->octeon_crypto); +} + +void helper_octeon_cp2_mt_hsh_startmd5(CPUMIPSState *env, uint64_t value) +{ + octeon_hsh_set_pair(env->octeon_crypto.hsh_dat, 7, value); + octeon_md5_transform(&env->octeon_crypto); +} + +void helper_octeon_cp2_mt_hsh_startsha256(CPUMIPSState *env, uint64_t value) +{ + octeon_hsh_set_pair(env->octeon_crypto.hsh_dat, 7, value); + octeon_sha256_transform(&env->octeon_crypto); +} + +void helper_octeon_cp2_mt_hsh_startsha(CPUMIPSState *env, uint64_t value) +{ + octeon_hsh_set_pair(env->octeon_crypto.hsh_dat, 7, value); + octeon_sha1_transform(&env->octeon_crypto); +} + +void helper_octeon_cp2_mt_hsh_startsha512(CPUMIPSState *env, uint64_t value) +{ + MIPSOcteonCryptoState *crypto = &env->octeon_crypto; + + crypto->hsh_dat[15] = value; + octeon_sha512_transform(crypto); +} + uint64_t helper_octeon_cp2_mf_crc_iv_reflect(CPUMIPSState *env) { return octeon_crc_reflect32_by_byte(env->octeon_crypto.crc_iv); From e3c6d52fa01c5513360ea75e13ae9479b8811e9c Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Mon, 8 Jun 2026 12:59:38 -0600 Subject: [PATCH 13/23] target/mips: add Octeon CHORD and LLM COP2 helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the Octeon CHORD hardware register access path and the LLM 36-bit and 64-bit read and write windows. Model both CHORD access forms, including the RDHWR $30 path and the legacy DMFC2 alias. Implement sparse backing storage for the two LLM sets so user-mode code can save, restore, and probe the architectural state without allocating a full hardware-sized backing array. Signed-off-by: James Hilliard Message-ID: <20260608-mips-octeon-missing-insns-v2-v16-13-daef7a0d8b04@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- target/mips/cpu.c | 67 +++++++++++++++++++++++++++++ target/mips/cpu.h | 5 +++ target/mips/helper.h | 9 ++++ target/mips/internal.h | 3 ++ target/mips/system/machine.c | 67 +++++++++++++++++++++++++++++ target/mips/tcg/octeon_crypto.c | 76 +++++++++++++++++++++++++++++++++ target/mips/tcg/op_helper.c | 6 +++ target/mips/tcg/translate.c | 8 ++++ 8 files changed, 241 insertions(+) diff --git a/target/mips/cpu.c b/target/mips/cpu.c index fccc7a711d..b223b767c9 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -26,6 +26,7 @@ #include "cpu.h" #include "internal.h" #include "qemu/module.h" +#include "qemu/qtree.h" #include "system/qtest.h" #include "hw/core/qdev-properties.h" #include "hw/core/qdev-clock.h" @@ -181,6 +182,57 @@ static bool mips_cpu_has_work(CPUState *cs) #include "cpu-defs.c.inc" +static gint mips_octeon_u64_tree_compare(gconstpointer a, gconstpointer b, + gpointer user_data) +{ + uint64_t av = *(const uint64_t *)a; + uint64_t bv = *(const uint64_t *)b; + + return (av > bv) - (av < bv); +} + +QTree *mips_octeon_llm_tree_new(void) +{ + return q_tree_new_full(mips_octeon_u64_tree_compare, + NULL, g_free, g_free); +} + +uint64_t mips_octeon_llm_load(QTree *tree, uint64_t addr) +{ + uint64_t key = addr; + uint64_t *value = tree ? q_tree_lookup(tree, &key) : NULL; + + return value ? *value : 0; +} + +void mips_octeon_llm_store(QTree **treep, uint64_t addr, uint64_t value) +{ + uint64_t *key; + uint64_t *stored; + + if (!*treep) { + *treep = mips_octeon_llm_tree_new(); + } + + key = g_new(uint64_t, 1); + stored = g_new(uint64_t, 1); + *key = addr; + *stored = value; + q_tree_replace(*treep, key, stored); +} + +static void mips_octeon_destroy_llm_state(MIPSOcteonCryptoState *crypto) +{ + if (crypto->llm36) { + q_tree_destroy(crypto->llm36); + crypto->llm36 = NULL; + } + if (crypto->llm64) { + q_tree_destroy(crypto->llm64); + crypto->llm64 = NULL; + } +} + static void mips_cpu_reset_hold(Object *obj, ResetType type) { CPUState *cs = CPU(obj); @@ -192,6 +244,7 @@ static void mips_cpu_reset_hold(Object *obj, ResetType type) mcc->parent_phases.hold(obj, type); } + mips_octeon_destroy_llm_state(&env->octeon_crypto); memset(env, 0, offsetof(CPUMIPSState, end_reset_fields)); /* Reset registers to their default values */ @@ -246,6 +299,9 @@ static void mips_cpu_reset_hold(Object *obj, ResetType type) env->active_fpu.fcr31 = env->cpu_model->CP1_fcr31; env->msair = env->cpu_model->MSAIR; env->insn_flags = env->cpu_model->insn_flags; + if (env->insn_flags & INSN_OCTEON) { + env->octeon_crypto.chord = 1; + } #if defined(CONFIG_USER_ONLY) env->CP0_Status = (MIPS_HFLAG_UM << CP0St_KSU); @@ -262,6 +318,9 @@ static void mips_cpu_reset_hold(Object *obj, ResetType type) * hardware registers. */ env->CP0_HWREna |= 0x0000000F; + if (env->insn_flags & INSN_OCTEON) { + env->CP0_HWREna |= 0x40000000u; + } if (env->CP0_Config1 & (1 << CP0C1_FP)) { env->CP0_Status |= (1 << CP0St_CU1); } @@ -417,6 +476,13 @@ static void mips_cpu_reset_hold(Object *obj, ResetType type) #endif } +static void mips_cpu_finalize(Object *obj) +{ + MIPSCPU *cpu = MIPS_CPU(obj); + + mips_octeon_destroy_llm_state(&cpu->env.octeon_crypto); +} + static void mips_cpu_disas_set_info(const CPUState *cs, disassemble_info *info) { const MIPSCPU *cpu = MIPS_CPU(cs); @@ -645,6 +711,7 @@ static const TypeInfo mips_cpu_type_info = { .instance_size = sizeof(MIPSCPU), .instance_align = __alignof(MIPSCPU), .instance_init = mips_cpu_initfn, + .instance_finalize = mips_cpu_finalize, .abstract = true, .class_size = sizeof(MIPSCPUClass), .class_init = mips_cpu_class_init, diff --git a/target/mips/cpu.h b/target/mips/cpu.h index 3df71adf9b..319147a948 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -11,6 +11,7 @@ #include "fpu/softfloat-types.h" #include "hw/core/clock.h" #include "mips-defs.h" +#include "qemu/qtree.h" typedef struct CPUMIPSTLBContext CPUMIPSTLBContext; @@ -559,6 +560,10 @@ typedef struct MIPSOcteonCryptoState { uint16_t gfm_poly; uint8_t aes_keylen; uint8_t crc_len; + uint64_t chord; + uint64_t llm_data[2]; + QTree *llm36; + QTree *llm64; } MIPSOcteonCryptoState; typedef struct CPUArchState { diff --git a/target/mips/helper.h b/target/mips/helper.h index 834f2d0769..e210e406f9 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -74,6 +74,14 @@ DEF_HELPER_2(octeon_cp2_mt_hsh_startmd5, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_hsh_startsha256, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_hsh_startsha, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_hsh_startsha512, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_llm_read_addr0, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_llm_write_addr0, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_llm_read64_addr0, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_llm_write64_addr0, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_llm_read_addr1, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_llm_write_addr1, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_llm_read64_addr1, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_llm_write64_addr1, void, env, i64) /* microMIPS functions */ DEF_HELPER_4(lwm, void, env, tl, tl, i32) @@ -245,6 +253,7 @@ DEF_HELPER_1(rdhwr_cc, tl, env) DEF_HELPER_1(rdhwr_ccres, tl, env) DEF_HELPER_1(rdhwr_performance, tl, env) DEF_HELPER_1(rdhwr_xnp, tl, env) +DEF_HELPER_1(rdhwr_chord, tl, env) DEF_HELPER_2(pmon, void, env, int) DEF_HELPER_1(wait, void, env) diff --git a/target/mips/internal.h b/target/mips/internal.h index aab77b1b25..c5c286872e 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -93,6 +93,9 @@ extern const int mips_defs_number; int mips_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int mips_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); +QTree *mips_octeon_llm_tree_new(void); +uint64_t mips_octeon_llm_load(QTree *tree, uint64_t addr); +void mips_octeon_llm_store(QTree **treep, uint64_t addr, uint64_t value); #define USEG_LIMIT ((target_ulong)(int32_t)0x7FFFFFFFUL) #define KSEG0_BASE ((target_ulong)(int32_t)0x80000000UL) diff --git a/target/mips/system/machine.c b/target/mips/system/machine.c index 77f576a25b..bd1e4002cf 100644 --- a/target/mips/system/machine.c +++ b/target/mips/system/machine.c @@ -131,6 +131,69 @@ static const VMStateDescription vmstate_octeon_multiplier_tc = { } }; +typedef struct OcteonLLMTreePutData { + QEMUFile *f; +} OcteonLLMTreePutData; + +static gboolean put_octeon_llm_tree_entry(gpointer key, gpointer value, + gpointer user_data) +{ + OcteonLLMTreePutData *data = user_data; + + qemu_put_be64(data->f, *(uint64_t *)key); + qemu_put_be64(data->f, *(uint64_t *)value); + return false; +} + +static int put_octeon_llm_tree(QEMUFile *f, void *pv, size_t size, + const VMStateField *field, JSONWriter *vmdesc) +{ + QTree *tree = *(QTree **)pv; + OcteonLLMTreePutData data = { .f = f }; + uint32_t nnodes = tree ? q_tree_nnodes(tree) : 0; + + qemu_put_be32(f, nnodes); + if (tree) { + q_tree_foreach(tree, put_octeon_llm_tree_entry, &data); + } + + return 0; +} + +static int get_octeon_llm_tree(QEMUFile *f, void *pv, size_t size, + const VMStateField *field) +{ + QTree **treep = pv; + uint32_t nnodes = qemu_get_be32(f); + + if (*treep) { + q_tree_destroy(*treep); + } + *treep = mips_octeon_llm_tree_new(); + + for (uint32_t i = 0; i < nnodes; i++) { + uint64_t addr = qemu_get_be64(f); + uint64_t value = qemu_get_be64(f); + + mips_octeon_llm_store(treep, addr, value); + } + + return 0; +} + +static const VMStateInfo vmstate_info_octeon_llm_tree = { + .name = "octeon_llm_tree", + .get = get_octeon_llm_tree, + .put = put_octeon_llm_tree, +}; + +#define VMSTATE_OCTEON_LLM_TREE(_f, _s) { \ + .name = stringify(_f), \ + .version_id = 1, \ + .info = &vmstate_info_octeon_llm_tree, \ + .offset = vmstate_offset_pointer(_s, _f, QTree), \ +} + /* MVP state */ static const VMStateDescription vmstate_mvp = { @@ -301,6 +364,10 @@ static const VMStateDescription mips_vmstate_octeon_crypto = { VMSTATE_UINT16(env.octeon_crypto.gfm_poly, MIPSCPU), VMSTATE_UINT8(env.octeon_crypto.aes_keylen, MIPSCPU), VMSTATE_UINT8(env.octeon_crypto.crc_len, MIPSCPU), + VMSTATE_UINT64(env.octeon_crypto.chord, MIPSCPU), + VMSTATE_UINT64_ARRAY(env.octeon_crypto.llm_data, MIPSCPU, 2), + VMSTATE_OCTEON_LLM_TREE(env.octeon_crypto.llm36, MIPSCPU), + VMSTATE_OCTEON_LLM_TREE(env.octeon_crypto.llm64, MIPSCPU), VMSTATE_END_OF_LIST() } }; diff --git a/target/mips/tcg/octeon_crypto.c b/target/mips/tcg/octeon_crypto.c index 82ad355d56..b24533e03d 100644 --- a/target/mips/tcg/octeon_crypto.c +++ b/target/mips/tcg/octeon_crypto.c @@ -16,6 +16,42 @@ #include "qemu/bitops.h" #include "qemu/host-utils.h" +#define OCTEON_LLM_NARROW_MASK ((1ULL << 36) - 1) + +static uint64_t octeon_llm_pack_narrow(uint64_t value) +{ + value &= OCTEON_LLM_NARROW_MASK; + return value | ((uint64_t)(ctpop64(value) & 1) << 36); +} + +static void octeon_llm_read(MIPSOcteonCryptoState *crypto, unsigned int set, + uint64_t addr, bool wide) +{ + uint64_t value; + + if (wide) { + value = mips_octeon_llm_load(crypto->llm64, addr); + } else { + value = octeon_llm_pack_narrow( + mips_octeon_llm_load(crypto->llm36, addr)); + } + + crypto->llm_data[set] = value; +} + +static void octeon_llm_write(MIPSOcteonCryptoState *crypto, unsigned int set, + uint64_t addr, bool wide) +{ + uint64_t value = crypto->llm_data[set]; + + if (wide) { + mips_octeon_llm_store(&crypto->llm64, addr, value); + } else { + mips_octeon_llm_store(&crypto->llm36, addr, + value & OCTEON_LLM_NARROW_MASK); + } +} + static uint32_t octeon_crc_reflect32_by_byte(uint32_t v) { return bswap32(revbit32(v)); @@ -2225,3 +2261,43 @@ void helper_octeon_cp2_mt_crc_write_var_reflect(CPUMIPSState *env, octeon_crc_update_reflect(crypto, value, MIN(8U, crypto->crc_len & 0xf)); } + +void helper_octeon_cp2_mt_llm_read_addr0(CPUMIPSState *env, uint64_t value) +{ + octeon_llm_read(&env->octeon_crypto, 0, value, false); +} + +void helper_octeon_cp2_mt_llm_write_addr0(CPUMIPSState *env, uint64_t value) +{ + octeon_llm_write(&env->octeon_crypto, 0, value, false); +} + +void helper_octeon_cp2_mt_llm_read64_addr0(CPUMIPSState *env, uint64_t value) +{ + octeon_llm_read(&env->octeon_crypto, 0, value, true); +} + +void helper_octeon_cp2_mt_llm_write64_addr0(CPUMIPSState *env, uint64_t value) +{ + octeon_llm_write(&env->octeon_crypto, 0, value, true); +} + +void helper_octeon_cp2_mt_llm_read_addr1(CPUMIPSState *env, uint64_t value) +{ + octeon_llm_read(&env->octeon_crypto, 1, value, false); +} + +void helper_octeon_cp2_mt_llm_write_addr1(CPUMIPSState *env, uint64_t value) +{ + octeon_llm_write(&env->octeon_crypto, 1, value, false); +} + +void helper_octeon_cp2_mt_llm_read64_addr1(CPUMIPSState *env, uint64_t value) +{ + octeon_llm_read(&env->octeon_crypto, 1, value, true); +} + +void helper_octeon_cp2_mt_llm_write64_addr1(CPUMIPSState *env, uint64_t value) +{ + octeon_llm_write(&env->octeon_crypto, 1, value, true); +} diff --git a/target/mips/tcg/op_helper.c b/target/mips/tcg/op_helper.c index 4502ae2b5b..3e586e3049 100644 --- a/target/mips/tcg/op_helper.c +++ b/target/mips/tcg/op_helper.c @@ -255,6 +255,12 @@ target_ulong helper_rdhwr_xnp(CPUMIPSState *env) return (env->CP0_Config5 >> CP0C5_XNP) & 1; } +target_ulong helper_rdhwr_chord(CPUMIPSState *env) +{ + check_hwrena(env, 30, GETPC()); + return env->octeon_crypto.chord; +} + void helper_pmon(CPUMIPSState *env, int function) { function /= 2; diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c index 123d2c89c3..1f44932882 100644 --- a/target/mips/tcg/translate.c +++ b/target/mips/tcg/translate.c @@ -10925,6 +10925,14 @@ void gen_rdhwr(DisasContext *ctx, int rt, int rd, int sel) } break; #endif + case 30: + if (!(ctx->insn_flags & INSN_OCTEON)) { + gen_reserved_instruction(ctx); + break; + } + gen_helper_rdhwr_chord(t0, tcg_env); + gen_store_gpr(t0, rt); + break; default: /* Invalid */ MIPS_INVAL("rdhwr"); gen_reserved_instruction(ctx); From e32e36298e2645bf7c18efd9a031827681235030 Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Mon, 8 Jun 2026 12:59:39 -0600 Subject: [PATCH 14/23] target/mips: decode Octeon COP2 register selectors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add explicit decodetree entries and translator bindings for Octeon DMFC2/DMTC2 selectors that are simple COP2 register transfers. Emit direct TCG loads and stores for register moves. Use signed 32-bit loads for 32-bit DMFC2 readback and mask narrow writable fields such as AESKEYLEN and CRCLEN on DMTC2. Keep operation selectors with side effects in later functional decode patches. Signed-off-by: James Hilliard Reviewed-by: Richard Henderson Message-ID: <20260608-mips-octeon-missing-insns-v2-v16-14-daef7a0d8b04@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- target/mips/tcg/octeon.decode | 80 +++++++ target/mips/tcg/octeon_translate.c | 210 ++++++++++++++++++ tests/tcg/mips/user/isa/octeon/octeon-insns.c | 89 ++++++++ 3 files changed, 379 insertions(+) diff --git a/target/mips/tcg/octeon.decode b/target/mips/tcg/octeon.decode index 1e44c588dd..09fbc6c1e3 100644 --- a/target/mips/tcg/octeon.decode +++ b/target/mips/tcg/octeon.decode @@ -97,3 +97,83 @@ LBUX 011111 ..... ..... ..... 00110 001010 @lx LWUX 011111 ..... ..... ..... 10000 001010 @lx LBX 011111 ..... ..... ..... 10110 001010 @lx LDX 011111 ..... ..... ..... 01000 001010 @lx + +# Selector-driven DMFC2/DMTC2 interfaces for Octeon COP2 engines. +&cp2 rt +{ + [ + CVM_MF_HSH_IV0 010010 00001 rt:5 0000 0000 0100 1000 &cp2 + CVM_MF_HSH_IV1 010010 00001 rt:5 0000 0000 0100 1001 &cp2 + CVM_MF_HSH_IV2 010010 00001 rt:5 0000 0000 0100 1010 &cp2 + CVM_MF_HSH_IV3 010010 00001 rt:5 0000 0000 0100 1011 &cp2 + CVM_MF_HSH_DAT0 010010 00001 rt:5 0000 0000 0100 0000 &cp2 + CVM_MF_HSH_DAT1 010010 00001 rt:5 0000 0000 0100 0001 &cp2 + CVM_MF_HSH_DAT2 010010 00001 rt:5 0000 0000 0100 0010 &cp2 + CVM_MF_HSH_DAT3 010010 00001 rt:5 0000 0000 0100 0011 &cp2 + CVM_MF_HSH_DAT4 010010 00001 rt:5 0000 0000 0100 0100 &cp2 + CVM_MF_HSH_DAT5 010010 00001 rt:5 0000 0000 0100 0101 &cp2 + CVM_MF_HSH_DAT6 010010 00001 rt:5 0000 0000 0100 0110 &cp2 + CVM_MF_3DES_KEY0 010010 00001 rt:5 0000 0000 1000 0000 &cp2 + CVM_MF_3DES_KEY1 010010 00001 rt:5 0000 0000 1000 0001 &cp2 + CVM_MF_3DES_KEY2 010010 00001 rt:5 0000 0000 1000 0010 &cp2 + CVM_MF_3DES_IV 010010 00001 rt:5 0000 0000 1000 0100 &cp2 + CVM_MF_3DES_RESULT 010010 00001 rt:5 0000 0000 1000 1000 &cp2 + CVM_MF_KAS_RESULT 010010 00001 rt:5 0000 0000 1001 1000 &cp2 + CVM_MF_AES_RESINP0 010010 00001 rt:5 0000 0001 0000 0000 &cp2 + CVM_MF_AES_RESINP1 010010 00001 rt:5 0000 0001 0000 0001 &cp2 + CVM_MF_AES_IV0 010010 00001 rt:5 0000 0001 0000 0010 &cp2 + CVM_MF_AES_IV1 010010 00001 rt:5 0000 0001 0000 0011 &cp2 + CVM_MF_AES_KEY0 010010 00001 rt:5 0000 0001 0000 0100 &cp2 + CVM_MF_AES_KEY1 010010 00001 rt:5 0000 0001 0000 0101 &cp2 + CVM_MF_AES_KEY2 010010 00001 rt:5 0000 0001 0000 0110 &cp2 + CVM_MF_AES_KEY3 010010 00001 rt:5 0000 0001 0000 0111 &cp2 + CVM_MF_AES_KEYLENGTH 010010 00001 rt:5 0000 0001 0001 0000 &cp2 + CVM_MF_AES_INP0 010010 00001 rt:5 0000 0001 0001 0001 &cp2 + CVM_MF_CRC_POLYNOMIAL 010010 00001 rt:5 0000 0010 0000 0000 &cp2 + CVM_MF_CRC_IV 010010 00001 rt:5 0000 0010 0000 0001 &cp2 + CVM_MF_CRC_LEN 010010 00001 rt:5 0000 0010 0000 0010 &cp2 + CVM_MF_GFM_MUL0 010010 00001 rt:5 0000 0010 0101 1000 &cp2 + CVM_MF_GFM_MUL1 010010 00001 rt:5 0000 0010 0101 1001 &cp2 + CVM_MF_GFM_RESINP0 010010 00001 rt:5 0000 0010 0101 1010 &cp2 + CVM_MF_GFM_RESINP1 010010 00001 rt:5 0000 0010 0101 1011 &cp2 + CVM_MF_GFM_POLY 010010 00001 rt:5 0000 0010 0101 1110 &cp2 + CVM_MT_HSH_DAT0 010010 00101 rt:5 0000 0000 0100 0000 &cp2 + CVM_MT_HSH_DAT1 010010 00101 rt:5 0000 0000 0100 0001 &cp2 + CVM_MT_HSH_DAT2 010010 00101 rt:5 0000 0000 0100 0010 &cp2 + CVM_MT_HSH_DAT3 010010 00101 rt:5 0000 0000 0100 0011 &cp2 + CVM_MT_HSH_DAT4 010010 00101 rt:5 0000 0000 0100 0100 &cp2 + CVM_MT_HSH_DAT5 010010 00101 rt:5 0000 0000 0100 0101 &cp2 + CVM_MT_HSH_DAT6 010010 00101 rt:5 0000 0000 0100 0110 &cp2 + CVM_MT_HSH_IV0 010010 00101 rt:5 0000 0000 0100 1000 &cp2 + CVM_MT_HSH_IV1 010010 00101 rt:5 0000 0000 0100 1001 &cp2 + CVM_MT_HSH_IV2 010010 00101 rt:5 0000 0000 0100 1010 &cp2 + CVM_MT_HSH_IV3 010010 00101 rt:5 0000 0000 0100 1011 &cp2 + CVM_MT_3DES_KEY0 010010 00101 rt:5 0000 0000 1000 0000 &cp2 + CVM_MT_3DES_KEY1 010010 00101 rt:5 0000 0000 1000 0001 &cp2 + CVM_MT_3DES_KEY2 010010 00101 rt:5 0000 0000 1000 0010 &cp2 + CVM_MT_3DES_IV 010010 00101 rt:5 0000 0000 1000 0100 &cp2 + CVM_MT_3DES_RESULT 010010 00101 rt:5 0000 0000 1001 1000 &cp2 + CVM_MT_AES_RESINP0 010010 00101 rt:5 0000 0001 0000 0000 &cp2 + CVM_MT_AES_RESINP1 010010 00101 rt:5 0000 0001 0000 0001 &cp2 + CVM_MT_AES_IV0 010010 00101 rt:5 0000 0001 0000 0010 &cp2 + CVM_MT_AES_IV1 010010 00101 rt:5 0000 0001 0000 0011 &cp2 + CVM_MT_AES_KEY0 010010 00101 rt:5 0000 0001 0000 0100 &cp2 + CVM_MT_AES_KEY1 010010 00101 rt:5 0000 0001 0000 0101 &cp2 + CVM_MT_AES_KEY2 010010 00101 rt:5 0000 0001 0000 0110 &cp2 + CVM_MT_AES_KEY3 010010 00101 rt:5 0000 0001 0000 0111 &cp2 + CVM_MT_AES_ENC_CBC0 010010 00101 rt:5 0000 0001 0000 1000 &cp2 + CVM_MT_AES_ENC0 010010 00101 rt:5 0000 0001 0000 1010 &cp2 + CVM_MT_AES_DEC_CBC0 010010 00101 rt:5 0000 0001 0000 1100 &cp2 + CVM_MT_AES_DEC0 010010 00101 rt:5 0000 0001 0000 1110 &cp2 + CVM_MT_AES_KEYLENGTH 010010 00101 rt:5 0000 0001 0001 0000 &cp2 + CVM_MT_CRC_IV 010010 00101 rt:5 0000 0010 0000 0001 &cp2 + CVM_MT_GFM_MUL0 010010 00101 rt:5 0000 0010 0101 1000 &cp2 + CVM_MT_GFM_MUL1 010010 00101 rt:5 0000 0010 0101 1001 &cp2 + CVM_MT_GFM_RESINP0 010010 00101 rt:5 0000 0010 0101 1010 &cp2 + CVM_MT_GFM_RESINP1 010010 00101 rt:5 0000 0010 0101 1011 &cp2 + CVM_MT_GFM_POLY 010010 00101 rt:5 0000 0010 0101 1110 &cp2 + CVM_MT_CRC_LEN 010010 00101 rt:5 0001 0010 0000 0010 &cp2 + CVM_MT_CRC_POLYNOMIAL 010010 00101 rt:5 0100 0010 0000 0000 &cp2 + ] + CP2_Undef 010010 ----- ----- ---- ---- ---- ---- +} diff --git a/target/mips/tcg/octeon_translate.c b/target/mips/tcg/octeon_translate.c index b0af2f4838..b33252dd1f 100644 --- a/target/mips/tcg/octeon_translate.c +++ b/target/mips/tcg/octeon_translate.c @@ -13,6 +13,216 @@ /* Include the auto-generated decoder. */ #include "decode-octeon.c.inc" +#define OCTEON_CRYPTO_OFFSET(FIELD) \ + offsetof(CPUMIPSState, octeon_crypto.FIELD) + +#define CP2_MF_I64(NAME, FIELD) \ + TRANS(NAME, trans_octeon_cp2_mf_i64, OCTEON_CRYPTO_OFFSET(FIELD)) +#define CP2_MF_S32(NAME, FIELD) \ + TRANS(NAME, trans_octeon_cp2_mf_s32, OCTEON_CRYPTO_OFFSET(FIELD)) +#define CP2_MF_U16(NAME, FIELD) \ + TRANS(NAME, trans_octeon_cp2_mf_u16, OCTEON_CRYPTO_OFFSET(FIELD)) +#define CP2_MF_U8(NAME, FIELD) \ + TRANS(NAME, trans_octeon_cp2_mf_u8, OCTEON_CRYPTO_OFFSET(FIELD)) +#define CP2_MF_HSH_PAIR(NAME, FIELD, INDEX) \ + TRANS(NAME, trans_octeon_cp2_mf_hsh_pair, \ + OCTEON_CRYPTO_OFFSET(FIELD[2 * (INDEX)]), \ + OCTEON_CRYPTO_OFFSET(FIELD[2 * (INDEX) + 1])) +#define CP2_MT_I64(NAME, FIELD) \ + TRANS(NAME, trans_octeon_cp2_mt_i64, OCTEON_CRYPTO_OFFSET(FIELD)) +#define CP2_MT_U32(NAME, FIELD) \ + TRANS(NAME, trans_octeon_cp2_mt_u32, OCTEON_CRYPTO_OFFSET(FIELD)) +#define CP2_MT_U16(NAME, FIELD) \ + TRANS(NAME, trans_octeon_cp2_mt_u16, OCTEON_CRYPTO_OFFSET(FIELD)) +#define CP2_MT_U8_MASKED(NAME, FIELD, MASK) \ + TRANS(NAME, trans_octeon_cp2_mt_u8_masked, \ + OCTEON_CRYPTO_OFFSET(FIELD), MASK) +#define CP2_MT_HSH_PAIR(NAME, FIELD, INDEX) \ + TRANS(NAME, trans_octeon_cp2_mt_hsh_pair, \ + OCTEON_CRYPTO_OFFSET(FIELD[2 * (INDEX)]), \ + OCTEON_CRYPTO_OFFSET(FIELD[2 * (INDEX) + 1])) + +#define OCTEON_LO32_OFFSET (HOST_BIG_ENDIAN ? 4 : 0) + +static bool trans_CP2_Undef(DisasContext *ctx, arg_CP2_Undef *a) +{ + generate_exception_err(ctx, EXCP_CpU, 2); + return true; +} + +static bool trans_octeon_cp2_mf_i64(DisasContext *ctx, arg_cp2 *a, int offset) +{ + TCGv_i64 value = tcg_temp_new_i64(); + + tcg_gen_ld_i64(value, tcg_env, offset); + gen_store_gpr(value, a->rt); + return true; +} + +static bool trans_octeon_cp2_mf_s32(DisasContext *ctx, arg_cp2 *a, int offset) +{ + TCGv_i64 value = tcg_temp_new_i64(); + + tcg_gen_ld32s_i64(value, tcg_env, offset); + gen_store_gpr(value, a->rt); + return true; +} + +static bool trans_octeon_cp2_mf_u16(DisasContext *ctx, arg_cp2 *a, int offset) +{ + TCGv_i64 value = tcg_temp_new_i64(); + + tcg_gen_ld16u_i64(value, tcg_env, offset); + gen_store_gpr(value, a->rt); + return true; +} + +static bool trans_octeon_cp2_mf_u8(DisasContext *ctx, arg_cp2 *a, int offset) +{ + TCGv_i64 value = tcg_temp_new_i64(); + + tcg_gen_ld8u_i64(value, tcg_env, offset); + gen_store_gpr(value, a->rt); + return true; +} + +static bool trans_octeon_cp2_mf_hsh_pair(DisasContext *ctx, arg_cp2 *a, + int hi_offset, int lo_offset) +{ + TCGv_i64 hi = tcg_temp_new_i64(); + TCGv_i64 lo = tcg_temp_new_i64(); + + tcg_gen_ld_i64(hi, tcg_env, hi_offset); + tcg_gen_ld_i64(lo, tcg_env, lo_offset); + tcg_gen_concat32_i64(lo, lo, hi); + gen_store_gpr(lo, a->rt); + return true; +} + +static bool trans_octeon_cp2_mt_i64(DisasContext *ctx, arg_cp2 *a, int offset) +{ + TCGv_i64 value = tcg_temp_new_i64(); + + gen_load_gpr(value, a->rt); + tcg_gen_st_i64(value, tcg_env, offset); + return true; +} + +static bool trans_octeon_cp2_mt_u32(DisasContext *ctx, arg_cp2 *a, int offset) +{ + TCGv_i64 value = tcg_temp_new_i64(); + + gen_load_gpr(value, a->rt); + tcg_gen_st32_i64(value, tcg_env, offset); + return true; +} + +static bool trans_octeon_cp2_mt_u16(DisasContext *ctx, arg_cp2 *a, int offset) +{ + TCGv_i64 value = tcg_temp_new_i64(); + + gen_load_gpr(value, a->rt); + tcg_gen_st16_i64(value, tcg_env, offset); + return true; +} + +static bool trans_octeon_cp2_mt_u8_masked(DisasContext *ctx, arg_cp2 *a, + int offset, uint8_t mask) +{ + TCGv_i64 value = tcg_temp_new_i64(); + + gen_load_gpr(value, a->rt); + tcg_gen_andi_i64(value, value, mask); + tcg_gen_st8_i64(value, tcg_env, offset); + return true; +} + +static bool trans_octeon_cp2_mt_hsh_pair(DisasContext *ctx, arg_cp2 *a, + int hi_offset, int lo_offset) +{ + TCGv_i64 value = tcg_temp_new_i64(); + + gen_load_gpr(value, a->rt); + tcg_gen_st32_i64(value, tcg_env, lo_offset + OCTEON_LO32_OFFSET); + tcg_gen_shri_i64(value, value, 32); + tcg_gen_st32_i64(value, tcg_env, hi_offset + OCTEON_LO32_OFFSET); + return true; +} + +CP2_MF_HSH_PAIR(CVM_MF_HSH_DAT0, hsh_dat, 0); +CP2_MF_HSH_PAIR(CVM_MF_HSH_DAT1, hsh_dat, 1); +CP2_MF_HSH_PAIR(CVM_MF_HSH_DAT2, hsh_dat, 2); +CP2_MF_HSH_PAIR(CVM_MF_HSH_DAT3, hsh_dat, 3); +CP2_MF_HSH_PAIR(CVM_MF_HSH_DAT4, hsh_dat, 4); +CP2_MF_HSH_PAIR(CVM_MF_HSH_DAT5, hsh_dat, 5); +CP2_MF_HSH_PAIR(CVM_MF_HSH_DAT6, hsh_dat, 6); +CP2_MF_HSH_PAIR(CVM_MF_HSH_IV0, hsh_iv, 0); +CP2_MF_HSH_PAIR(CVM_MF_HSH_IV1, hsh_iv, 1); +CP2_MF_HSH_PAIR(CVM_MF_HSH_IV2, hsh_iv, 2); +CP2_MF_HSH_PAIR(CVM_MF_HSH_IV3, hsh_iv, 3); +CP2_MF_I64(CVM_MF_3DES_KEY0, des3_key[0]); +CP2_MF_I64(CVM_MF_3DES_KEY1, des3_key[1]); +CP2_MF_I64(CVM_MF_3DES_KEY2, des3_key[2]); +CP2_MF_I64(CVM_MF_3DES_IV, des3_iv); +CP2_MF_I64(CVM_MF_3DES_RESULT, des3_result); +CP2_MF_I64(CVM_MF_KAS_RESULT, des3_result); +CP2_MF_I64(CVM_MF_AES_RESINP0, aes_resinp[0]); +CP2_MF_I64(CVM_MF_AES_RESINP1, aes_resinp[1]); +CP2_MF_I64(CVM_MF_AES_IV0, aes_iv[0]); +CP2_MF_I64(CVM_MF_AES_IV1, aes_iv[1]); +CP2_MF_I64(CVM_MF_AES_KEY0, aes_key[0]); +CP2_MF_I64(CVM_MF_AES_KEY1, aes_key[1]); +CP2_MF_I64(CVM_MF_AES_KEY2, aes_key[2]); +CP2_MF_I64(CVM_MF_AES_KEY3, aes_key[3]); +CP2_MF_U8(CVM_MF_AES_KEYLENGTH, aes_keylen); +CP2_MF_I64(CVM_MF_AES_INP0, aes_resinp[0]); +CP2_MF_S32(CVM_MF_CRC_POLYNOMIAL, crc_poly); +CP2_MF_S32(CVM_MF_CRC_IV, crc_iv); +CP2_MF_U8(CVM_MF_CRC_LEN, crc_len); +CP2_MF_I64(CVM_MF_GFM_MUL0, gfm_mul[0]); +CP2_MF_I64(CVM_MF_GFM_MUL1, gfm_mul[1]); +CP2_MF_I64(CVM_MF_GFM_RESINP0, gfm_resinp[0]); +CP2_MF_I64(CVM_MF_GFM_RESINP1, gfm_resinp[1]); +CP2_MF_U16(CVM_MF_GFM_POLY, gfm_poly); + +CP2_MT_HSH_PAIR(CVM_MT_HSH_DAT0, hsh_dat, 0); +CP2_MT_HSH_PAIR(CVM_MT_HSH_DAT1, hsh_dat, 1); +CP2_MT_HSH_PAIR(CVM_MT_HSH_DAT2, hsh_dat, 2); +CP2_MT_HSH_PAIR(CVM_MT_HSH_DAT3, hsh_dat, 3); +CP2_MT_HSH_PAIR(CVM_MT_HSH_DAT4, hsh_dat, 4); +CP2_MT_HSH_PAIR(CVM_MT_HSH_DAT5, hsh_dat, 5); +CP2_MT_HSH_PAIR(CVM_MT_HSH_DAT6, hsh_dat, 6); +CP2_MT_HSH_PAIR(CVM_MT_HSH_IV0, hsh_iv, 0); +CP2_MT_HSH_PAIR(CVM_MT_HSH_IV1, hsh_iv, 1); +CP2_MT_HSH_PAIR(CVM_MT_HSH_IV2, hsh_iv, 2); +CP2_MT_HSH_PAIR(CVM_MT_HSH_IV3, hsh_iv, 3); +CP2_MT_I64(CVM_MT_3DES_KEY0, des3_key[0]); +CP2_MT_I64(CVM_MT_3DES_KEY1, des3_key[1]); +CP2_MT_I64(CVM_MT_3DES_KEY2, des3_key[2]); +CP2_MT_I64(CVM_MT_3DES_IV, des3_iv); +CP2_MT_I64(CVM_MT_3DES_RESULT, des3_result); +CP2_MT_I64(CVM_MT_AES_RESINP0, aes_resinp[0]); +CP2_MT_I64(CVM_MT_AES_RESINP1, aes_resinp[1]); +CP2_MT_I64(CVM_MT_AES_IV0, aes_iv[0]); +CP2_MT_I64(CVM_MT_AES_IV1, aes_iv[1]); +CP2_MT_I64(CVM_MT_AES_KEY0, aes_key[0]); +CP2_MT_I64(CVM_MT_AES_KEY1, aes_key[1]); +CP2_MT_I64(CVM_MT_AES_KEY2, aes_key[2]); +CP2_MT_I64(CVM_MT_AES_KEY3, aes_key[3]); +CP2_MT_I64(CVM_MT_AES_ENC_CBC0, aes_resinp[0]); +CP2_MT_I64(CVM_MT_AES_ENC0, aes_resinp[0]); +CP2_MT_I64(CVM_MT_AES_DEC_CBC0, aes_resinp[0]); +CP2_MT_I64(CVM_MT_AES_DEC0, aes_resinp[0]); +CP2_MT_U8_MASKED(CVM_MT_AES_KEYLENGTH, aes_keylen, 3); +CP2_MT_U32(CVM_MT_CRC_IV, crc_iv); +CP2_MT_I64(CVM_MT_GFM_MUL0, gfm_mul[0]); +CP2_MT_I64(CVM_MT_GFM_MUL1, gfm_mul[1]); +CP2_MT_I64(CVM_MT_GFM_RESINP0, gfm_resinp[0]); +CP2_MT_I64(CVM_MT_GFM_RESINP1, gfm_resinp[1]); +CP2_MT_U16(CVM_MT_GFM_POLY, gfm_poly); +CP2_MT_U8_MASKED(CVM_MT_CRC_LEN, crc_len, 0xf); +CP2_MT_U32(CVM_MT_CRC_POLYNOMIAL, crc_poly); + static bool trans_BBIT(DisasContext *ctx, arg_BBIT *a) { TCGv_i64 p; diff --git a/tests/tcg/mips/user/isa/octeon/octeon-insns.c b/tests/tcg/mips/user/isa/octeon/octeon-insns.c index 9153e37e9e..7a7445c40a 100644 --- a/tests/tcg/mips/user/isa/octeon/octeon-insns.c +++ b/tests/tcg/mips/user/isa/octeon/octeon-insns.c @@ -186,6 +186,86 @@ static uint64_t octeon_mtp0_zeroes_p1(void) return rd; } +static uint64_t octeon_cop2_key0_readback(uint64_t value) +{ + uint64_t rd; + + asm volatile( + "move $8, %[value]\n\t" + ".word 0x48a80104\n\t" /* dmtc2 $8, AES_KEY0 selector */ + ".word 0x482a0104\n\t" /* dmfc2 $10, AES_KEY0 selector */ + "move %[rd], $10\n\t" + : [rd] "=r" (rd) + : [value] "r" (value) + : "$8", "$10"); + + return rd; +} + +static uint64_t octeon_cop2_key2_readback(uint64_t value) +{ + uint64_t rd; + + asm volatile( + "move $8, %[value]\n\t" + ".word 0x48a80106\n\t" /* dmtc2 $8, AES_KEY2 selector */ + ".word 0x482a0106\n\t" /* dmfc2 $10, AES_KEY2 selector */ + "move %[rd], $10\n\t" + : [rd] "=r" (rd) + : [value] "r" (value) + : "$8", "$10"); + + return rd; +} + +static uint64_t octeon_cop2_key3_readback(uint64_t value) +{ + uint64_t rd; + + asm volatile( + "move $8, %[value]\n\t" + ".word 0x48a80107\n\t" /* dmtc2 $8, AES_KEY3 selector */ + ".word 0x482a0107\n\t" /* dmfc2 $10, AES_KEY3 selector */ + "move %[rd], $10\n\t" + : [rd] "=r" (rd) + : [value] "r" (value) + : "$8", "$10"); + + return rd; +} + +static uint64_t octeon_cop2_keylength_readback(uint64_t value) +{ + uint64_t rd; + + asm volatile( + "move $8, %[value]\n\t" + ".word 0x48a80110\n\t" /* dmtc2 $8, AES_KEYLENGTH selector */ + ".word 0x482a0110\n\t" /* dmfc2 $10, AES_KEYLENGTH selector */ + "move %[rd], $10\n\t" + : [rd] "=r" (rd) + : [value] "r" (value) + : "$8", "$10"); + + return rd; +} + +static uint64_t octeon_cop2_hsh_dat0_readback(uint64_t value) +{ + uint64_t rd; + + asm volatile( + "move $8, %[value]\n\t" + ".word 0x48a80040\n\t" /* dmtc2 $8, HSH_DAT0 selector */ + ".word 0x482a0040\n\t" /* dmfc2 $10, HSH_DAT0 selector */ + "move %[rd], $10\n\t" + : [rd] "=r" (rd) + : [value] "r" (value) + : "$8", "$10"); + + return rd; +} + int main(void) { assert(octeon_baddu(0x123, 0x0f0) == 0x13); @@ -199,6 +279,15 @@ int main(void) assert(octeon_vmm0(5, 13, 7, 11) == 59); assert(octeon_vmm0_zeroes_mpl1() == 0); assert(octeon_mtp0_zeroes_p1() == 0); + assert(octeon_cop2_key0_readback(0x1122334455667788ULL) == + 0x1122334455667788ULL); + assert(octeon_cop2_key2_readback(0x8877665544332211ULL) == + 0x8877665544332211ULL); + assert(octeon_cop2_key3_readback(0x0102030405060708ULL) == + 0x0102030405060708ULL); + assert(octeon_cop2_keylength_readback(0xa5) == 1); + assert(octeon_cop2_hsh_dat0_readback(0x0102030405060708ULL) == + 0x0102030405060708ULL); return 0; } From 9679d839f8457ec0f62100cf42f8f6e877f2c66b Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Mon, 8 Jun 2026 12:59:40 -0600 Subject: [PATCH 15/23] target/mips: decode Octeon CRC and GFM COP2 selectors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add explicit decodetree entries and translator bindings for the Octeon CRC and GFM COP2 operation selectors. Unlike simple register moves, these selectors update CRC or Galois-field state and therefore remain per-operation helper calls. Keep CRC/GFM decode next to the helpers that implement these side effects while avoiding a monolithic selector-dispatch helper. Signed-off-by: James Hilliard Reviewed-by: Richard Henderson Message-ID: <20260608-mips-octeon-missing-insns-v2-v16-15-daef7a0d8b04@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- target/mips/helper.h | 1 + target/mips/tcg/octeon.decode | 22 ++++++ target/mips/tcg/octeon_crypto.c | 7 ++ target/mips/tcg/octeon_translate.c | 50 +++++++++++++ tests/tcg/mips/user/isa/octeon/octeon-insns.c | 70 +++++++++++++++++++ 5 files changed, 150 insertions(+) diff --git a/target/mips/helper.h b/target/mips/helper.h index e210e406f9..141350e80a 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -32,6 +32,7 @@ DEF_HELPER_1(octeon_cp2_mf_gfm_mul_reflect1, i64, env) DEF_HELPER_1(octeon_cp2_mf_gfm_resinp_reflect0, i64, env) DEF_HELPER_1(octeon_cp2_mf_gfm_resinp_reflect1, i64, env) DEF_HELPER_2(octeon_cp2_mt_crc_write_iv_reflect, void, env, i64) +DEF_HELPER_2(octeon_cp2_mt_crc_write_polynomial_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) diff --git a/target/mips/tcg/octeon.decode b/target/mips/tcg/octeon.decode index 09fbc6c1e3..70e02d0b0e 100644 --- a/target/mips/tcg/octeon.decode +++ b/target/mips/tcg/octeon.decode @@ -132,6 +132,11 @@ LDX 011111 ..... ..... ..... 01000 001010 @lx CVM_MF_CRC_POLYNOMIAL 010010 00001 rt:5 0000 0010 0000 0000 &cp2 CVM_MF_CRC_IV 010010 00001 rt:5 0000 0010 0000 0001 &cp2 CVM_MF_CRC_LEN 010010 00001 rt:5 0000 0010 0000 0010 &cp2 + CVM_MF_CRC_IV_REFLECT 010010 00001 rt:5 0000 0010 0000 0011 &cp2 + CVM_MF_GFM_MUL_REFLECT0 010010 00001 rt:5 0000 0000 0101 1000 &cp2 + CVM_MF_GFM_MUL_REFLECT1 010010 00001 rt:5 0000 0000 0101 1001 &cp2 + CVM_MF_GFM_RESINP_REFLECT0 010010 00001 rt:5 0000 0000 0101 1010 &cp2 + CVM_MF_GFM_RESINP_REFLECT1 010010 00001 rt:5 0000 0000 0101 1011 &cp2 CVM_MF_GFM_MUL0 010010 00001 rt:5 0000 0010 0101 1000 &cp2 CVM_MF_GFM_MUL1 010010 00001 rt:5 0000 0010 0101 1001 &cp2 CVM_MF_GFM_RESINP0 010010 00001 rt:5 0000 0010 0101 1010 &cp2 @@ -148,6 +153,9 @@ LDX 011111 ..... ..... ..... 01000 001010 @lx CVM_MT_HSH_IV1 010010 00101 rt:5 0000 0000 0100 1001 &cp2 CVM_MT_HSH_IV2 010010 00101 rt:5 0000 0000 0100 1010 &cp2 CVM_MT_HSH_IV3 010010 00101 rt:5 0000 0000 0100 1011 &cp2 + CVM_MT_GFM_MUL_REFLECT0 010010 00101 rt:5 0000 0000 0101 1000 &cp2 + CVM_MT_GFM_MUL_REFLECT1 010010 00101 rt:5 0000 0000 0101 1001 &cp2 + CVM_MT_GFM_XOR0_REFLECT 010010 00101 rt:5 0000 0000 0101 1100 &cp2 CVM_MT_3DES_KEY0 010010 00101 rt:5 0000 0000 1000 0000 &cp2 CVM_MT_3DES_KEY1 010010 00101 rt:5 0000 0000 1000 0001 &cp2 CVM_MT_3DES_KEY2 010010 00101 rt:5 0000 0000 1000 0010 &cp2 @@ -167,13 +175,27 @@ LDX 011111 ..... ..... ..... 01000 001010 @lx CVM_MT_AES_DEC0 010010 00101 rt:5 0000 0001 0000 1110 &cp2 CVM_MT_AES_KEYLENGTH 010010 00101 rt:5 0000 0001 0001 0000 &cp2 CVM_MT_CRC_IV 010010 00101 rt:5 0000 0010 0000 0001 &cp2 + CVM_MT_CRC_IV_REFLECT 010010 00101 rt:5 0000 0010 0001 0001 &cp2 + CVM_MT_CRC_BYTE 010010 00101 rt:5 0000 0010 0000 0100 &cp2 + CVM_MT_CRC_HALF 010010 00101 rt:5 0000 0010 0000 0101 &cp2 + CVM_MT_CRC_WORD 010010 00101 rt:5 0000 0010 0000 0110 &cp2 + CVM_MT_CRC_BYTE_REFLECT 010010 00101 rt:5 0000 0010 0001 0100 &cp2 + CVM_MT_CRC_HALF_REFLECT 010010 00101 rt:5 0000 0010 0001 0101 &cp2 + CVM_MT_CRC_WORD_REFLECT 010010 00101 rt:5 0000 0010 0001 0110 &cp2 CVM_MT_GFM_MUL0 010010 00101 rt:5 0000 0010 0101 1000 &cp2 CVM_MT_GFM_MUL1 010010 00101 rt:5 0000 0010 0101 1001 &cp2 CVM_MT_GFM_RESINP0 010010 00101 rt:5 0000 0010 0101 1010 &cp2 CVM_MT_GFM_RESINP1 010010 00101 rt:5 0000 0010 0101 1011 &cp2 CVM_MT_GFM_POLY 010010 00101 rt:5 0000 0010 0101 1110 &cp2 CVM_MT_CRC_LEN 010010 00101 rt:5 0001 0010 0000 0010 &cp2 + CVM_MT_CRC_DWORD 010010 00101 rt:5 0001 0010 0000 0111 &cp2 + CVM_MT_CRC_VAR 010010 00101 rt:5 0001 0010 0000 1000 &cp2 + CVM_MT_CRC_DWORD_REFLECT 010010 00101 rt:5 0001 0010 0001 0111 &cp2 + CVM_MT_CRC_VAR_REFLECT 010010 00101 rt:5 0001 0010 0001 1000 &cp2 + CVM_MT_GFM_XORMUL1_REFLECT 010010 00101 rt:5 0100 0000 0101 1101 &cp2 CVM_MT_CRC_POLYNOMIAL 010010 00101 rt:5 0100 0010 0000 0000 &cp2 + CVM_MT_CRC_POLYNOMIAL_REFLECT 010010 00101 rt:5 0100 0010 0001 0000 &cp2 + CVM_MT_GFM_XORMUL1 010010 00101 rt:5 0100 0010 0101 1101 &cp2 ] CP2_Undef 010010 ----- ----- ---- ---- ---- ---- } diff --git a/target/mips/tcg/octeon_crypto.c b/target/mips/tcg/octeon_crypto.c index b24533e03d..fbf80be2a5 100644 --- a/target/mips/tcg/octeon_crypto.c +++ b/target/mips/tcg/octeon_crypto.c @@ -2203,6 +2203,13 @@ void helper_octeon_cp2_mt_crc_write_iv_reflect(CPUMIPSState *env, octeon_crc_reflect32_by_byte((uint32_t)value); } +void helper_octeon_cp2_mt_crc_write_polynomial_reflect(CPUMIPSState *env, + uint64_t value) +{ + env->octeon_crypto.crc_poly = + 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); diff --git a/target/mips/tcg/octeon_translate.c b/target/mips/tcg/octeon_translate.c index b33252dd1f..ce4cfcb3f3 100644 --- a/target/mips/tcg/octeon_translate.c +++ b/target/mips/tcg/octeon_translate.c @@ -28,6 +28,9 @@ TRANS(NAME, trans_octeon_cp2_mf_hsh_pair, \ OCTEON_CRYPTO_OFFSET(FIELD[2 * (INDEX)]), \ OCTEON_CRYPTO_OFFSET(FIELD[2 * (INDEX) + 1])) +#define CP2_MF_HELPER(NAME, SUFFIX) \ + TRANS(NAME, trans_octeon_cp2_mf_helper, \ + gen_helper_octeon_cp2_mf_ ## SUFFIX) #define CP2_MT_I64(NAME, FIELD) \ TRANS(NAME, trans_octeon_cp2_mt_i64, OCTEON_CRYPTO_OFFSET(FIELD)) #define CP2_MT_U32(NAME, FIELD) \ @@ -41,6 +44,9 @@ TRANS(NAME, trans_octeon_cp2_mt_hsh_pair, \ OCTEON_CRYPTO_OFFSET(FIELD[2 * (INDEX)]), \ OCTEON_CRYPTO_OFFSET(FIELD[2 * (INDEX) + 1])) +#define CP2_MT_HELPER(NAME, SUFFIX) \ + TRANS(NAME, trans_octeon_cp2_mt_helper, \ + gen_helper_octeon_cp2_mt_ ## SUFFIX) #define OCTEON_LO32_OFFSET (HOST_BIG_ENDIAN ? 4 : 0) @@ -99,6 +105,16 @@ static bool trans_octeon_cp2_mf_hsh_pair(DisasContext *ctx, arg_cp2 *a, return true; } +static bool trans_octeon_cp2_mf_helper(DisasContext *ctx, arg_cp2 *a, + void (*gen_helper)(TCGv_i64, TCGv_env)) +{ + TCGv_i64 value = tcg_temp_new_i64(); + + gen_helper(value, tcg_env); + gen_store_gpr(value, a->rt); + return true; +} + static bool trans_octeon_cp2_mt_i64(DisasContext *ctx, arg_cp2 *a, int offset) { TCGv_i64 value = tcg_temp_new_i64(); @@ -149,6 +165,16 @@ static bool trans_octeon_cp2_mt_hsh_pair(DisasContext *ctx, arg_cp2 *a, return true; } +static bool trans_octeon_cp2_mt_helper(DisasContext *ctx, arg_cp2 *a, + void (*gen_helper)(TCGv_env, TCGv_i64)) +{ + TCGv_i64 value = tcg_temp_new_i64(); + + gen_load_gpr(value, a->rt); + gen_helper(tcg_env, value); + return true; +} + CP2_MF_HSH_PAIR(CVM_MF_HSH_DAT0, hsh_dat, 0); CP2_MF_HSH_PAIR(CVM_MF_HSH_DAT1, hsh_dat, 1); CP2_MF_HSH_PAIR(CVM_MF_HSH_DAT2, hsh_dat, 2); @@ -185,6 +211,12 @@ CP2_MF_I64(CVM_MF_GFM_RESINP0, gfm_resinp[0]); CP2_MF_I64(CVM_MF_GFM_RESINP1, gfm_resinp[1]); CP2_MF_U16(CVM_MF_GFM_POLY, gfm_poly); +CP2_MF_HELPER(CVM_MF_CRC_IV_REFLECT, crc_iv_reflect); +CP2_MF_HELPER(CVM_MF_GFM_MUL_REFLECT0, gfm_mul_reflect0); +CP2_MF_HELPER(CVM_MF_GFM_MUL_REFLECT1, gfm_mul_reflect1); +CP2_MF_HELPER(CVM_MF_GFM_RESINP_REFLECT0, gfm_resinp_reflect0); +CP2_MF_HELPER(CVM_MF_GFM_RESINP_REFLECT1, gfm_resinp_reflect1); + CP2_MT_HSH_PAIR(CVM_MT_HSH_DAT0, hsh_dat, 0); CP2_MT_HSH_PAIR(CVM_MT_HSH_DAT1, hsh_dat, 1); CP2_MT_HSH_PAIR(CVM_MT_HSH_DAT2, hsh_dat, 2); @@ -196,6 +228,9 @@ CP2_MT_HSH_PAIR(CVM_MT_HSH_IV0, hsh_iv, 0); CP2_MT_HSH_PAIR(CVM_MT_HSH_IV1, hsh_iv, 1); CP2_MT_HSH_PAIR(CVM_MT_HSH_IV2, hsh_iv, 2); CP2_MT_HSH_PAIR(CVM_MT_HSH_IV3, hsh_iv, 3); +CP2_MT_HELPER(CVM_MT_GFM_MUL_REFLECT0, gfm_mul_reflect0); +CP2_MT_HELPER(CVM_MT_GFM_MUL_REFLECT1, gfm_mul_reflect1); +CP2_MT_HELPER(CVM_MT_GFM_XOR0_REFLECT, gfm_xor0_reflect); CP2_MT_I64(CVM_MT_3DES_KEY0, des3_key[0]); CP2_MT_I64(CVM_MT_3DES_KEY1, des3_key[1]); CP2_MT_I64(CVM_MT_3DES_KEY2, des3_key[2]); @@ -223,6 +258,21 @@ CP2_MT_U16(CVM_MT_GFM_POLY, gfm_poly); CP2_MT_U8_MASKED(CVM_MT_CRC_LEN, crc_len, 0xf); CP2_MT_U32(CVM_MT_CRC_POLYNOMIAL, crc_poly); +CP2_MT_HELPER(CVM_MT_CRC_POLYNOMIAL_REFLECT, crc_write_polynomial_reflect); +CP2_MT_HELPER(CVM_MT_CRC_IV_REFLECT, crc_write_iv_reflect); +CP2_MT_HELPER(CVM_MT_CRC_BYTE, crc_write_byte); +CP2_MT_HELPER(CVM_MT_CRC_HALF, crc_write_half); +CP2_MT_HELPER(CVM_MT_CRC_WORD, crc_write_word); +CP2_MT_HELPER(CVM_MT_CRC_BYTE_REFLECT, crc_write_byte_reflect); +CP2_MT_HELPER(CVM_MT_CRC_HALF_REFLECT, crc_write_half_reflect); +CP2_MT_HELPER(CVM_MT_CRC_WORD_REFLECT, crc_write_word_reflect); +CP2_MT_HELPER(CVM_MT_CRC_DWORD, crc_write_dword); +CP2_MT_HELPER(CVM_MT_CRC_VAR, crc_write_var); +CP2_MT_HELPER(CVM_MT_CRC_DWORD_REFLECT, crc_write_dword_reflect); +CP2_MT_HELPER(CVM_MT_CRC_VAR_REFLECT, crc_write_var_reflect); +CP2_MT_HELPER(CVM_MT_GFM_XORMUL1_REFLECT, gfm_xormul1_reflect); +CP2_MT_HELPER(CVM_MT_GFM_XORMUL1, gfm_xormul1); + static bool trans_BBIT(DisasContext *ctx, arg_BBIT *a) { TCGv_i64 p; diff --git a/tests/tcg/mips/user/isa/octeon/octeon-insns.c b/tests/tcg/mips/user/isa/octeon/octeon-insns.c index 7a7445c40a..f3c52d7829 100644 --- a/tests/tcg/mips/user/isa/octeon/octeon-insns.c +++ b/tests/tcg/mips/user/isa/octeon/octeon-insns.c @@ -266,6 +266,70 @@ static uint64_t octeon_cop2_hsh_dat0_readback(uint64_t value) return rd; } +static uint64_t octeon_cop2_crc_len_readback(uint64_t value) +{ + uint64_t rd; + + asm volatile( + "move $8, %[value]\n\t" + ".word 0x48a81202\n\t" /* dmtc2 $8, CRC_LEN selector */ + ".word 0x482a0202\n\t" /* dmfc2 $10, CRC_LEN selector */ + "move %[rd], $10\n\t" + : [rd] "=r" (rd) + : [value] "r" (value) + : "$8", "$10"); + + return rd; +} + +static uint64_t octeon_cop2_crc_poly_reflect_readback(uint64_t value) +{ + uint64_t rd; + + asm volatile( + "move $8, %[value]\n\t" + ".word 0x48a84210\n\t" /* dmtc2 $8, CRC_POLYNOMIAL_REFLECT selector */ + ".word 0x482a0200\n\t" /* dmfc2 $10, CRC_POLYNOMIAL selector */ + "move %[rd], $10\n\t" + : [rd] "=r" (rd) + : [value] "r" (value) + : "$8", "$10"); + + return rd; +} + +static uint64_t octeon_cop2_gfm_mul_reflect_write_readback(uint64_t value) +{ + uint64_t rd; + + asm volatile( + "move $8, %[value]\n\t" + ".word 0x48a80058\n\t" /* dmtc2 $8, GFM_MUL_REFLECT0 selector */ + ".word 0x482a0258\n\t" /* dmfc2 $10, GFM_MUL0 selector */ + "move %[rd], $10\n\t" + : [rd] "=r" (rd) + : [value] "r" (value) + : "$8", "$10"); + + return rd; +} + +static uint64_t octeon_cop2_gfm_mul_reflect_readback(uint64_t value) +{ + uint64_t rd; + + asm volatile( + "move $8, %[value]\n\t" + ".word 0x48a80258\n\t" /* dmtc2 $8, GFM_MUL0 selector */ + ".word 0x482a0058\n\t" /* dmfc2 $10, GFM_MUL_REFLECT0 selector */ + "move %[rd], $10\n\t" + : [rd] "=r" (rd) + : [value] "r" (value) + : "$8", "$10"); + + return rd; +} + int main(void) { assert(octeon_baddu(0x123, 0x0f0) == 0x13); @@ -288,6 +352,12 @@ int main(void) assert(octeon_cop2_keylength_readback(0xa5) == 1); assert(octeon_cop2_hsh_dat0_readback(0x0102030405060708ULL) == 0x0102030405060708ULL); + assert(octeon_cop2_crc_len_readback(0xb5) == 5); + assert(octeon_cop2_crc_poly_reflect_readback(0x12345678) == 0x482c6a1e); + assert(octeon_cop2_gfm_mul_reflect_write_readback( + 0x0123456789abcdefULL) == 0xf7b3d591e6a2c480ULL); + assert(octeon_cop2_gfm_mul_reflect_readback( + 0xfedcba9876543210ULL) == 0x084c2a6e195d3b7fULL); return 0; } From ac28df97e51dd6c7cd80d7003ef189c1df1db17b Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Mon, 8 Jun 2026 12:59:41 -0600 Subject: [PATCH 16/23] target/mips: decode Octeon HSH and SHA3 COP2 selectors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add explicit decodetree entries and translator bindings for the Octeon HSH shared-window selectors and SHA3 operation selectors. Simple SHA3 DAT register moves and XORDAT selectors use direct TCG transfers, while HSH operation selectors and SHA3 STARTOP remain helper-backed for their visible side effects. Keep HSH/SHA3 decode separate from direct register transfers because the shared hash-window aliases and side-effecting operations need their own selector coverage. Signed-off-by: James Hilliard Reviewed-by: Richard Henderson Message-ID: <20260608-mips-octeon-missing-insns-v2-v16-16-daef7a0d8b04@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- target/mips/tcg/octeon.decode | 77 ++++++++++++++++++++++ target/mips/tcg/octeon_translate.c | 102 +++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+) diff --git a/target/mips/tcg/octeon.decode b/target/mips/tcg/octeon.decode index 70e02d0b0e..b1a63b743f 100644 --- a/target/mips/tcg/octeon.decode +++ b/target/mips/tcg/octeon.decode @@ -113,6 +113,7 @@ LDX 011111 ..... ..... ..... 01000 001010 @lx CVM_MF_HSH_DAT4 010010 00001 rt:5 0000 0000 0100 0100 &cp2 CVM_MF_HSH_DAT5 010010 00001 rt:5 0000 0000 0100 0101 &cp2 CVM_MF_HSH_DAT6 010010 00001 rt:5 0000 0000 0100 0110 &cp2 + CVM_MF_SHA3_DAT24 010010 00001 rt:5 0000 0000 0101 0000 &cp2 CVM_MF_3DES_KEY0 010010 00001 rt:5 0000 0000 1000 0000 &cp2 CVM_MF_3DES_KEY1 010010 00001 rt:5 0000 0000 1000 0001 &cp2 CVM_MF_3DES_KEY2 010010 00001 rt:5 0000 0000 1000 0010 &cp2 @@ -137,6 +138,30 @@ LDX 011111 ..... ..... ..... 01000 001010 @lx CVM_MF_GFM_MUL_REFLECT1 010010 00001 rt:5 0000 0000 0101 1001 &cp2 CVM_MF_GFM_RESINP_REFLECT0 010010 00001 rt:5 0000 0000 0101 1010 &cp2 CVM_MF_GFM_RESINP_REFLECT1 010010 00001 rt:5 0000 0000 0101 1011 &cp2 + CVM_MF_HSH_DATW0 010010 00001 rt:5 0000 0010 0100 0000 &cp2 + CVM_MF_HSH_DATW1 010010 00001 rt:5 0000 0010 0100 0001 &cp2 + CVM_MF_HSH_DATW2 010010 00001 rt:5 0000 0010 0100 0010 &cp2 + CVM_MF_HSH_DATW3 010010 00001 rt:5 0000 0010 0100 0011 &cp2 + CVM_MF_HSH_DATW4 010010 00001 rt:5 0000 0010 0100 0100 &cp2 + CVM_MF_HSH_DATW5 010010 00001 rt:5 0000 0010 0100 0101 &cp2 + CVM_MF_HSH_DATW6 010010 00001 rt:5 0000 0010 0100 0110 &cp2 + CVM_MF_HSH_DATW7 010010 00001 rt:5 0000 0010 0100 0111 &cp2 + CVM_MF_HSH_DATW8 010010 00001 rt:5 0000 0010 0100 1000 &cp2 + CVM_MF_HSH_DATW9 010010 00001 rt:5 0000 0010 0100 1001 &cp2 + CVM_MF_HSH_DATW10 010010 00001 rt:5 0000 0010 0100 1010 &cp2 + CVM_MF_HSH_DATW11 010010 00001 rt:5 0000 0010 0100 1011 &cp2 + CVM_MF_HSH_DATW12 010010 00001 rt:5 0000 0010 0100 1100 &cp2 + CVM_MF_HSH_DATW13 010010 00001 rt:5 0000 0010 0100 1101 &cp2 + CVM_MF_HSH_DATW14 010010 00001 rt:5 0000 0010 0100 1110 &cp2 + CVM_MF_HSH_DATW15 010010 00001 rt:5 0000 0010 0100 1111 &cp2 + CVM_MF_HSH_IVW0 010010 00001 rt:5 0000 0010 0101 0000 &cp2 + CVM_MF_HSH_IVW1 010010 00001 rt:5 0000 0010 0101 0001 &cp2 + CVM_MF_HSH_IVW2 010010 00001 rt:5 0000 0010 0101 0010 &cp2 + CVM_MF_HSH_IVW3 010010 00001 rt:5 0000 0010 0101 0011 &cp2 + CVM_MF_HSH_IVW4 010010 00001 rt:5 0000 0010 0101 0100 &cp2 + CVM_MF_HSH_IVW5 010010 00001 rt:5 0000 0010 0101 0101 &cp2 + CVM_MF_HSH_IVW6 010010 00001 rt:5 0000 0010 0101 0110 &cp2 + CVM_MF_HSH_IVW7 010010 00001 rt:5 0000 0010 0101 0111 &cp2 CVM_MF_GFM_MUL0 010010 00001 rt:5 0000 0010 0101 1000 &cp2 CVM_MF_GFM_MUL1 010010 00001 rt:5 0000 0010 0101 1001 &cp2 CVM_MF_GFM_RESINP0 010010 00001 rt:5 0000 0010 0101 1010 &cp2 @@ -153,6 +178,10 @@ LDX 011111 ..... ..... ..... 01000 001010 @lx CVM_MT_HSH_IV1 010010 00101 rt:5 0000 0000 0100 1001 &cp2 CVM_MT_HSH_IV2 010010 00101 rt:5 0000 0000 0100 1010 &cp2 CVM_MT_HSH_IV3 010010 00101 rt:5 0000 0000 0100 1011 &cp2 + CVM_MT_SHA3_DAT24 010010 00101 rt:5 0000 0000 0101 0000 &cp2 + CVM_MT_SHA3_DAT15 010010 00101 rt:5 0000 0000 0101 0001 &cp2 + # Cavium SDK code uses 0x0057 as a STARTSHA1 compatibility alias. + CVM_MT_HSH_STARTSHA1_COMPAT 010010 00101 rt:5 0000 0000 0101 0111 &cp2 CVM_MT_GFM_MUL_REFLECT0 010010 00101 rt:5 0000 0000 0101 1000 &cp2 CVM_MT_GFM_MUL_REFLECT1 010010 00101 rt:5 0000 0000 0101 1001 &cp2 CVM_MT_GFM_XOR0_REFLECT 010010 00101 rt:5 0000 0000 0101 1100 &cp2 @@ -182,19 +211,67 @@ LDX 011111 ..... ..... ..... 01000 001010 @lx CVM_MT_CRC_BYTE_REFLECT 010010 00101 rt:5 0000 0010 0001 0100 &cp2 CVM_MT_CRC_HALF_REFLECT 010010 00101 rt:5 0000 0010 0001 0101 &cp2 CVM_MT_CRC_WORD_REFLECT 010010 00101 rt:5 0000 0010 0001 0110 &cp2 + CVM_MT_HSH_DATW0 010010 00101 rt:5 0000 0010 0100 0000 &cp2 + CVM_MT_HSH_DATW1 010010 00101 rt:5 0000 0010 0100 0001 &cp2 + CVM_MT_HSH_DATW2 010010 00101 rt:5 0000 0010 0100 0010 &cp2 + CVM_MT_HSH_DATW3 010010 00101 rt:5 0000 0010 0100 0011 &cp2 + CVM_MT_HSH_DATW4 010010 00101 rt:5 0000 0010 0100 0100 &cp2 + CVM_MT_HSH_DATW5 010010 00101 rt:5 0000 0010 0100 0101 &cp2 + CVM_MT_HSH_DATW6 010010 00101 rt:5 0000 0010 0100 0110 &cp2 + CVM_MT_HSH_DATW7 010010 00101 rt:5 0000 0010 0100 0111 &cp2 + CVM_MT_HSH_DATW8 010010 00101 rt:5 0000 0010 0100 1000 &cp2 + CVM_MT_HSH_DATW9 010010 00101 rt:5 0000 0010 0100 1001 &cp2 + CVM_MT_HSH_DATW10 010010 00101 rt:5 0000 0010 0100 1010 &cp2 + CVM_MT_HSH_DATW11 010010 00101 rt:5 0000 0010 0100 1011 &cp2 + CVM_MT_HSH_DATW12 010010 00101 rt:5 0000 0010 0100 1100 &cp2 + CVM_MT_HSH_DATW13 010010 00101 rt:5 0000 0010 0100 1101 &cp2 + CVM_MT_HSH_DATW14 010010 00101 rt:5 0000 0010 0100 1110 &cp2 + CVM_MT_HSH_DATW15 010010 00101 rt:5 0000 0010 0100 1111 &cp2 + CVM_MT_HSH_IVW0 010010 00101 rt:5 0000 0010 0101 0000 &cp2 + CVM_MT_HSH_IVW1 010010 00101 rt:5 0000 0010 0101 0001 &cp2 + CVM_MT_HSH_IVW2 010010 00101 rt:5 0000 0010 0101 0010 &cp2 + CVM_MT_HSH_IVW3 010010 00101 rt:5 0000 0010 0101 0011 &cp2 + CVM_MT_HSH_IVW4 010010 00101 rt:5 0000 0010 0101 0100 &cp2 + CVM_MT_HSH_IVW5 010010 00101 rt:5 0000 0010 0101 0101 &cp2 + CVM_MT_HSH_IVW6 010010 00101 rt:5 0000 0010 0101 0110 &cp2 + CVM_MT_HSH_IVW7 010010 00101 rt:5 0000 0010 0101 0111 &cp2 CVM_MT_GFM_MUL0 010010 00101 rt:5 0000 0010 0101 1000 &cp2 CVM_MT_GFM_MUL1 010010 00101 rt:5 0000 0010 0101 1001 &cp2 CVM_MT_GFM_RESINP0 010010 00101 rt:5 0000 0010 0101 1010 &cp2 CVM_MT_GFM_RESINP1 010010 00101 rt:5 0000 0010 0101 1011 &cp2 + CVM_MT_GFM_XOR0 010010 00101 rt:5 0000 0010 0101 1100 &cp2 CVM_MT_GFM_POLY 010010 00101 rt:5 0000 0010 0101 1110 &cp2 + CVM_MT_SHA3_XORDAT0 010010 00101 rt:5 0000 0010 1100 0000 &cp2 + CVM_MT_SHA3_XORDAT1 010010 00101 rt:5 0000 0010 1100 0001 &cp2 + CVM_MT_SHA3_XORDAT2 010010 00101 rt:5 0000 0010 1100 0010 &cp2 + CVM_MT_SHA3_XORDAT3 010010 00101 rt:5 0000 0010 1100 0011 &cp2 + CVM_MT_SHA3_XORDAT4 010010 00101 rt:5 0000 0010 1100 0100 &cp2 + CVM_MT_SHA3_XORDAT5 010010 00101 rt:5 0000 0010 1100 0101 &cp2 + CVM_MT_SHA3_XORDAT6 010010 00101 rt:5 0000 0010 1100 0110 &cp2 + CVM_MT_SHA3_XORDAT7 010010 00101 rt:5 0000 0010 1100 0111 &cp2 + CVM_MT_SHA3_XORDAT8 010010 00101 rt:5 0000 0010 1100 1000 &cp2 + CVM_MT_SHA3_XORDAT9 010010 00101 rt:5 0000 0010 1100 1001 &cp2 + CVM_MT_SHA3_XORDAT10 010010 00101 rt:5 0000 0010 1100 1010 &cp2 + CVM_MT_SHA3_XORDAT11 010010 00101 rt:5 0000 0010 1100 1011 &cp2 + CVM_MT_SHA3_XORDAT12 010010 00101 rt:5 0000 0010 1100 1100 &cp2 + CVM_MT_SHA3_XORDAT13 010010 00101 rt:5 0000 0010 1100 1101 &cp2 + CVM_MT_SHA3_XORDAT14 010010 00101 rt:5 0000 0010 1100 1110 &cp2 + CVM_MT_SHA3_XORDAT15 010010 00101 rt:5 0000 0010 1100 1111 &cp2 + CVM_MT_SHA3_XORDAT16 010010 00101 rt:5 0000 0010 1101 0000 &cp2 + CVM_MT_SHA3_XORDAT17 010010 00101 rt:5 0000 0010 1101 0001 &cp2 CVM_MT_CRC_LEN 010010 00101 rt:5 0001 0010 0000 0010 &cp2 CVM_MT_CRC_DWORD 010010 00101 rt:5 0001 0010 0000 0111 &cp2 CVM_MT_CRC_VAR 010010 00101 rt:5 0001 0010 0000 1000 &cp2 CVM_MT_CRC_DWORD_REFLECT 010010 00101 rt:5 0001 0010 0001 0111 &cp2 CVM_MT_CRC_VAR_REFLECT 010010 00101 rt:5 0001 0010 0001 1000 &cp2 + CVM_MT_HSH_STARTMD5 010010 00101 rt:5 0100 0000 0100 0111 &cp2 + CVM_MT_HSH_STARTSHA256 010010 00101 rt:5 0100 0000 0100 1111 &cp2 + CVM_MT_SHA3_STARTOP 010010 00101 rt:5 0100 0000 0101 0010 &cp2 + CVM_MT_HSH_STARTSHA 010010 00101 rt:5 0100 0000 0101 0111 &cp2 CVM_MT_GFM_XORMUL1_REFLECT 010010 00101 rt:5 0100 0000 0101 1101 &cp2 CVM_MT_CRC_POLYNOMIAL 010010 00101 rt:5 0100 0010 0000 0000 &cp2 CVM_MT_CRC_POLYNOMIAL_REFLECT 010010 00101 rt:5 0100 0010 0001 0000 &cp2 + CVM_MT_HSH_STARTSHA512 010010 00101 rt:5 0100 0010 0100 1111 &cp2 CVM_MT_GFM_XORMUL1 010010 00101 rt:5 0100 0010 0101 1101 &cp2 ] CP2_Undef 010010 ----- ----- ---- ---- ---- ---- diff --git a/target/mips/tcg/octeon_translate.c b/target/mips/tcg/octeon_translate.c index ce4cfcb3f3..5497e5a6ce 100644 --- a/target/mips/tcg/octeon_translate.c +++ b/target/mips/tcg/octeon_translate.c @@ -47,6 +47,11 @@ #define CP2_MT_HELPER(NAME, SUFFIX) \ TRANS(NAME, trans_octeon_cp2_mt_helper, \ gen_helper_octeon_cp2_mt_ ## SUFFIX) +#define CP2_MT_HELPER_ENV(NAME, SUFFIX) \ + TRANS(NAME, trans_octeon_cp2_mt_helper_env, \ + gen_helper_octeon_cp2_mt_ ## SUFFIX) +#define CP2_MT_XOR_I64(NAME, FIELD) \ + TRANS(NAME, trans_octeon_cp2_mt_xor_i64, OCTEON_CRYPTO_OFFSET(FIELD)) #define OCTEON_LO32_OFFSET (HOST_BIG_ENDIAN ? 4 : 0) @@ -165,6 +170,19 @@ static bool trans_octeon_cp2_mt_hsh_pair(DisasContext *ctx, arg_cp2 *a, return true; } +static bool trans_octeon_cp2_mt_xor_i64(DisasContext *ctx, arg_cp2 *a, + int offset) +{ + TCGv_i64 value = tcg_temp_new_i64(); + TCGv_i64 old = tcg_temp_new_i64(); + + gen_load_gpr(value, a->rt); + tcg_gen_ld_i64(old, tcg_env, offset); + tcg_gen_xor_i64(old, old, value); + tcg_gen_st_i64(old, tcg_env, offset); + return true; +} + static bool trans_octeon_cp2_mt_helper(DisasContext *ctx, arg_cp2 *a, void (*gen_helper)(TCGv_env, TCGv_i64)) { @@ -175,6 +193,13 @@ static bool trans_octeon_cp2_mt_helper(DisasContext *ctx, arg_cp2 *a, return true; } +static bool trans_octeon_cp2_mt_helper_env(DisasContext *ctx, arg_cp2 *a, + void (*gen_helper)(TCGv_env)) +{ + gen_helper(tcg_env); + return true; +} + CP2_MF_HSH_PAIR(CVM_MF_HSH_DAT0, hsh_dat, 0); CP2_MF_HSH_PAIR(CVM_MF_HSH_DAT1, hsh_dat, 1); CP2_MF_HSH_PAIR(CVM_MF_HSH_DAT2, hsh_dat, 2); @@ -212,10 +237,35 @@ CP2_MF_I64(CVM_MF_GFM_RESINP1, gfm_resinp[1]); CP2_MF_U16(CVM_MF_GFM_POLY, gfm_poly); CP2_MF_HELPER(CVM_MF_CRC_IV_REFLECT, crc_iv_reflect); +CP2_MF_I64(CVM_MF_SHA3_DAT24, sha3_dat24); CP2_MF_HELPER(CVM_MF_GFM_MUL_REFLECT0, gfm_mul_reflect0); CP2_MF_HELPER(CVM_MF_GFM_MUL_REFLECT1, gfm_mul_reflect1); CP2_MF_HELPER(CVM_MF_GFM_RESINP_REFLECT0, gfm_resinp_reflect0); CP2_MF_HELPER(CVM_MF_GFM_RESINP_REFLECT1, gfm_resinp_reflect1); +CP2_MF_I64(CVM_MF_HSH_DATW0, hsh_dat[0]); +CP2_MF_I64(CVM_MF_HSH_DATW1, hsh_dat[1]); +CP2_MF_I64(CVM_MF_HSH_DATW2, hsh_dat[2]); +CP2_MF_I64(CVM_MF_HSH_DATW3, hsh_dat[3]); +CP2_MF_I64(CVM_MF_HSH_DATW4, hsh_dat[4]); +CP2_MF_I64(CVM_MF_HSH_DATW5, hsh_dat[5]); +CP2_MF_I64(CVM_MF_HSH_DATW6, hsh_dat[6]); +CP2_MF_I64(CVM_MF_HSH_DATW7, hsh_dat[7]); +CP2_MF_I64(CVM_MF_HSH_DATW8, hsh_dat[8]); +CP2_MF_I64(CVM_MF_HSH_DATW9, hsh_dat[9]); +CP2_MF_I64(CVM_MF_HSH_DATW10, hsh_dat[10]); +CP2_MF_I64(CVM_MF_HSH_DATW11, hsh_dat[11]); +CP2_MF_I64(CVM_MF_HSH_DATW12, hsh_dat[12]); +CP2_MF_I64(CVM_MF_HSH_DATW13, hsh_dat[13]); +CP2_MF_I64(CVM_MF_HSH_DATW14, hsh_dat[14]); +CP2_MF_I64(CVM_MF_HSH_DATW15, hsh_dat[15]); +CP2_MF_I64(CVM_MF_HSH_IVW0, hsh_iv[0]); +CP2_MF_I64(CVM_MF_HSH_IVW1, hsh_iv[1]); +CP2_MF_I64(CVM_MF_HSH_IVW2, hsh_iv[2]); +CP2_MF_I64(CVM_MF_HSH_IVW3, hsh_iv[3]); +CP2_MF_I64(CVM_MF_HSH_IVW4, hsh_iv[4]); +CP2_MF_I64(CVM_MF_HSH_IVW5, hsh_iv[5]); +CP2_MF_I64(CVM_MF_HSH_IVW6, hsh_iv[6]); +CP2_MF_I64(CVM_MF_HSH_IVW7, hsh_iv[7]); CP2_MT_HSH_PAIR(CVM_MT_HSH_DAT0, hsh_dat, 0); CP2_MT_HSH_PAIR(CVM_MT_HSH_DAT1, hsh_dat, 1); @@ -254,11 +304,13 @@ CP2_MT_I64(CVM_MT_GFM_MUL0, gfm_mul[0]); CP2_MT_I64(CVM_MT_GFM_MUL1, gfm_mul[1]); CP2_MT_I64(CVM_MT_GFM_RESINP0, gfm_resinp[0]); CP2_MT_I64(CVM_MT_GFM_RESINP1, gfm_resinp[1]); +CP2_MT_XOR_I64(CVM_MT_GFM_XOR0, gfm_resinp[0]); CP2_MT_U16(CVM_MT_GFM_POLY, gfm_poly); CP2_MT_U8_MASKED(CVM_MT_CRC_LEN, crc_len, 0xf); CP2_MT_U32(CVM_MT_CRC_POLYNOMIAL, crc_poly); CP2_MT_HELPER(CVM_MT_CRC_POLYNOMIAL_REFLECT, crc_write_polynomial_reflect); + CP2_MT_HELPER(CVM_MT_CRC_IV_REFLECT, crc_write_iv_reflect); CP2_MT_HELPER(CVM_MT_CRC_BYTE, crc_write_byte); CP2_MT_HELPER(CVM_MT_CRC_HALF, crc_write_half); @@ -272,6 +324,56 @@ CP2_MT_HELPER(CVM_MT_CRC_DWORD_REFLECT, crc_write_dword_reflect); CP2_MT_HELPER(CVM_MT_CRC_VAR_REFLECT, crc_write_var_reflect); CP2_MT_HELPER(CVM_MT_GFM_XORMUL1_REFLECT, gfm_xormul1_reflect); CP2_MT_HELPER(CVM_MT_GFM_XORMUL1, gfm_xormul1); +CP2_MT_I64(CVM_MT_SHA3_DAT24, sha3_dat24); +CP2_MT_I64(CVM_MT_SHA3_DAT15, hsh_dat[15]); +CP2_MT_XOR_I64(CVM_MT_SHA3_XORDAT0, sha3_dat[0]); +CP2_MT_XOR_I64(CVM_MT_SHA3_XORDAT1, sha3_dat[1]); +CP2_MT_XOR_I64(CVM_MT_SHA3_XORDAT2, sha3_dat[2]); +CP2_MT_XOR_I64(CVM_MT_SHA3_XORDAT3, sha3_dat[3]); +CP2_MT_XOR_I64(CVM_MT_SHA3_XORDAT4, sha3_dat[4]); +CP2_MT_XOR_I64(CVM_MT_SHA3_XORDAT5, sha3_dat[5]); +CP2_MT_XOR_I64(CVM_MT_SHA3_XORDAT6, sha3_dat[6]); +CP2_MT_XOR_I64(CVM_MT_SHA3_XORDAT7, sha3_dat[7]); +CP2_MT_XOR_I64(CVM_MT_SHA3_XORDAT8, sha3_dat[8]); +CP2_MT_XOR_I64(CVM_MT_SHA3_XORDAT9, sha3_dat[9]); +CP2_MT_XOR_I64(CVM_MT_SHA3_XORDAT10, sha3_dat[10]); +CP2_MT_XOR_I64(CVM_MT_SHA3_XORDAT11, sha3_dat[11]); +CP2_MT_XOR_I64(CVM_MT_SHA3_XORDAT12, sha3_dat[12]); +CP2_MT_XOR_I64(CVM_MT_SHA3_XORDAT13, sha3_dat[13]); +CP2_MT_XOR_I64(CVM_MT_SHA3_XORDAT14, sha3_dat[14]); +CP2_MT_XOR_I64(CVM_MT_SHA3_XORDAT15, sha3_dat[15]); +CP2_MT_XOR_I64(CVM_MT_SHA3_XORDAT16, sha3_dat[16]); +CP2_MT_XOR_I64(CVM_MT_SHA3_XORDAT17, sha3_dat[17]); +CP2_MT_HELPER_ENV(CVM_MT_SHA3_STARTOP, sha3_startop); +CP2_MT_HELPER(CVM_MT_HSH_STARTSHA1_COMPAT, hsh_startsha1_compat); +CP2_MT_I64(CVM_MT_HSH_DATW0, hsh_dat[0]); +CP2_MT_I64(CVM_MT_HSH_DATW1, hsh_dat[1]); +CP2_MT_I64(CVM_MT_HSH_DATW2, hsh_dat[2]); +CP2_MT_I64(CVM_MT_HSH_DATW3, hsh_dat[3]); +CP2_MT_I64(CVM_MT_HSH_DATW4, hsh_dat[4]); +CP2_MT_I64(CVM_MT_HSH_DATW5, hsh_dat[5]); +CP2_MT_I64(CVM_MT_HSH_DATW6, hsh_dat[6]); +CP2_MT_I64(CVM_MT_HSH_DATW7, hsh_dat[7]); +CP2_MT_I64(CVM_MT_HSH_DATW8, hsh_dat[8]); +CP2_MT_I64(CVM_MT_HSH_DATW9, hsh_dat[9]); +CP2_MT_I64(CVM_MT_HSH_DATW10, hsh_dat[10]); +CP2_MT_I64(CVM_MT_HSH_DATW11, hsh_dat[11]); +CP2_MT_I64(CVM_MT_HSH_DATW12, hsh_dat[12]); +CP2_MT_I64(CVM_MT_HSH_DATW13, hsh_dat[13]); +CP2_MT_I64(CVM_MT_HSH_DATW14, hsh_dat[14]); +CP2_MT_I64(CVM_MT_HSH_DATW15, hsh_dat[15]); +CP2_MT_I64(CVM_MT_HSH_IVW0, hsh_iv[0]); +CP2_MT_I64(CVM_MT_HSH_IVW1, hsh_iv[1]); +CP2_MT_I64(CVM_MT_HSH_IVW2, hsh_iv[2]); +CP2_MT_I64(CVM_MT_HSH_IVW3, hsh_iv[3]); +CP2_MT_I64(CVM_MT_HSH_IVW4, hsh_iv[4]); +CP2_MT_I64(CVM_MT_HSH_IVW5, hsh_iv[5]); +CP2_MT_I64(CVM_MT_HSH_IVW6, hsh_iv[6]); +CP2_MT_I64(CVM_MT_HSH_IVW7, hsh_iv[7]); +CP2_MT_HELPER(CVM_MT_HSH_STARTMD5, hsh_startmd5); +CP2_MT_HELPER(CVM_MT_HSH_STARTSHA256, hsh_startsha256); +CP2_MT_HELPER(CVM_MT_HSH_STARTSHA, hsh_startsha); +CP2_MT_HELPER(CVM_MT_HSH_STARTSHA512, hsh_startsha512); static bool trans_BBIT(DisasContext *ctx, arg_BBIT *a) { From b6ed5076a39421b65761c04b2d9cbfac594ac004 Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Mon, 8 Jun 2026 12:59:42 -0600 Subject: [PATCH 17/23] target/mips: decode Octeon ZUC and SNOW3G COP2 selectors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add explicit decodetree entries and translator bindings for the Octeon ZUC and SNOW3G COP2 operation selectors. These stream-cipher selectors operate on the shared HSH register window state, so dispatch them through the per-operation helpers added with the corresponding engine support. Keep stream-cipher decode separate because these selectors share the HSH register window with unrelated engines. Signed-off-by: James Hilliard Reviewed-by: Richard Henderson Message-ID: <20260608-mips-octeon-missing-insns-v2-v16-17-daef7a0d8b04@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- target/mips/tcg/octeon.decode | 4 ++++ target/mips/tcg/octeon_translate.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/target/mips/tcg/octeon.decode b/target/mips/tcg/octeon.decode index b1a63b743f..2b27fa205f 100644 --- a/target/mips/tcg/octeon.decode +++ b/target/mips/tcg/octeon.decode @@ -265,8 +265,12 @@ LDX 011111 ..... ..... ..... 01000 001010 @lx CVM_MT_CRC_DWORD_REFLECT 010010 00101 rt:5 0001 0010 0001 0111 &cp2 CVM_MT_CRC_VAR_REFLECT 010010 00101 rt:5 0001 0010 0001 1000 &cp2 CVM_MT_HSH_STARTMD5 010010 00101 rt:5 0100 0000 0100 0111 &cp2 + CVM_MT_SNOW3G_START 010010 00101 rt:5 0100 0000 0100 1101 &cp2 + CVM_MT_SNOW3G_MORE 010010 00101 rt:5 0100 0000 0100 1110 &cp2 CVM_MT_HSH_STARTSHA256 010010 00101 rt:5 0100 0000 0100 1111 &cp2 CVM_MT_SHA3_STARTOP 010010 00101 rt:5 0100 0000 0101 0010 &cp2 + CVM_MT_ZUC_START 010010 00101 rt:5 0100 0000 0101 0101 &cp2 + CVM_MT_ZUC_MORE 010010 00101 rt:5 0100 0000 0101 0110 &cp2 CVM_MT_HSH_STARTSHA 010010 00101 rt:5 0100 0000 0101 0111 &cp2 CVM_MT_GFM_XORMUL1_REFLECT 010010 00101 rt:5 0100 0000 0101 1101 &cp2 CVM_MT_CRC_POLYNOMIAL 010010 00101 rt:5 0100 0010 0000 0000 &cp2 diff --git a/target/mips/tcg/octeon_translate.c b/target/mips/tcg/octeon_translate.c index 5497e5a6ce..b4663b35a3 100644 --- a/target/mips/tcg/octeon_translate.c +++ b/target/mips/tcg/octeon_translate.c @@ -345,6 +345,10 @@ CP2_MT_XOR_I64(CVM_MT_SHA3_XORDAT15, sha3_dat[15]); CP2_MT_XOR_I64(CVM_MT_SHA3_XORDAT16, sha3_dat[16]); CP2_MT_XOR_I64(CVM_MT_SHA3_XORDAT17, sha3_dat[17]); CP2_MT_HELPER_ENV(CVM_MT_SHA3_STARTOP, sha3_startop); +CP2_MT_HELPER(CVM_MT_ZUC_START, zuc_start); +CP2_MT_HELPER(CVM_MT_ZUC_MORE, zuc_more); +CP2_MT_HELPER(CVM_MT_SNOW3G_START, snow3g_start); +CP2_MT_HELPER(CVM_MT_SNOW3G_MORE, snow3g_more); CP2_MT_HELPER(CVM_MT_HSH_STARTSHA1_COMPAT, hsh_startsha1_compat); CP2_MT_I64(CVM_MT_HSH_DATW0, hsh_dat[0]); CP2_MT_I64(CVM_MT_HSH_DATW1, hsh_dat[1]); From ec931476cdf98909e54811620f53d5337a19058f Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Mon, 8 Jun 2026 12:59:43 -0600 Subject: [PATCH 18/23] target/mips: decode Octeon block-cipher COP2 selectors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add explicit decodetree entries and translator bindings for the Octeon AES, SMS4, 3DES, KASUMI, and Camellia COP2 operation selectors. These selectors consume or update engine state, so keep them as per-operation helper calls while the simple block-cipher register moves remain direct TCG loads and stores from the earlier register-selector patch. This completes the block-cipher selector coverage without reintroducing a generic runtime selector dispatch path. Signed-off-by: James Hilliard Reviewed-by: Richard Henderson Message-ID: <20260608-mips-octeon-missing-insns-v2-v16-18-daef7a0d8b04@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- target/mips/tcg/octeon.decode | 17 +++++++++++++++++ target/mips/tcg/octeon_translate.c | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/target/mips/tcg/octeon.decode b/target/mips/tcg/octeon.decode index 2b27fa205f..4ac38d264c 100644 --- a/target/mips/tcg/octeon.decode +++ b/target/mips/tcg/octeon.decode @@ -203,6 +203,8 @@ LDX 011111 ..... ..... ..... 01000 001010 @lx CVM_MT_AES_DEC_CBC0 010010 00101 rt:5 0000 0001 0000 1100 &cp2 CVM_MT_AES_DEC0 010010 00101 rt:5 0000 0001 0000 1110 &cp2 CVM_MT_AES_KEYLENGTH 010010 00101 rt:5 0000 0001 0001 0000 &cp2 + CVM_MT_CAMELLIA_FL 010010 00101 rt:5 0000 0001 0001 0101 &cp2 + CVM_MT_CAMELLIA_FLINV 010010 00101 rt:5 0000 0001 0001 0110 &cp2 CVM_MT_CRC_IV 010010 00101 rt:5 0000 0010 0000 0001 &cp2 CVM_MT_CRC_IV_REFLECT 010010 00101 rt:5 0000 0010 0001 0001 &cp2 CVM_MT_CRC_BYTE 010010 00101 rt:5 0000 0010 0000 0100 &cp2 @@ -264,6 +266,15 @@ LDX 011111 ..... ..... ..... 01000 001010 @lx CVM_MT_CRC_VAR 010010 00101 rt:5 0001 0010 0000 1000 &cp2 CVM_MT_CRC_DWORD_REFLECT 010010 00101 rt:5 0001 0010 0001 0111 &cp2 CVM_MT_CRC_VAR_REFLECT 010010 00101 rt:5 0001 0010 0001 1000 &cp2 + CVM_MT_AES_ENC_CBC1 010010 00101 rt:5 0011 0001 0000 1001 &cp2 + CVM_MT_AES_ENC1 010010 00101 rt:5 0011 0001 0000 1011 &cp2 + CVM_MT_AES_DEC_CBC1 010010 00101 rt:5 0011 0001 0000 1101 &cp2 + CVM_MT_AES_DEC1 010010 00101 rt:5 0011 0001 0000 1111 &cp2 + CVM_MT_CAMELLIA_ROUND 010010 00101 rt:5 0011 0001 0001 0100 &cp2 + CVM_MT_SMS4_ENC_CBC1 010010 00101 rt:5 0011 0001 0001 1001 &cp2 + CVM_MT_SMS4_ENC1 010010 00101 rt:5 0011 0001 0001 1011 &cp2 + CVM_MT_SMS4_DEC_CBC1 010010 00101 rt:5 0011 0001 0001 1101 &cp2 + CVM_MT_SMS4_DEC1 010010 00101 rt:5 0011 0001 0001 1111 &cp2 CVM_MT_HSH_STARTMD5 010010 00101 rt:5 0100 0000 0100 0111 &cp2 CVM_MT_SNOW3G_START 010010 00101 rt:5 0100 0000 0100 1101 &cp2 CVM_MT_SNOW3G_MORE 010010 00101 rt:5 0100 0000 0100 1110 &cp2 @@ -273,6 +284,12 @@ LDX 011111 ..... ..... ..... 01000 001010 @lx CVM_MT_ZUC_MORE 010010 00101 rt:5 0100 0000 0101 0110 &cp2 CVM_MT_HSH_STARTSHA 010010 00101 rt:5 0100 0000 0101 0111 &cp2 CVM_MT_GFM_XORMUL1_REFLECT 010010 00101 rt:5 0100 0000 0101 1101 &cp2 + CVM_MT_3DES_ENC_CBC 010010 00101 rt:5 0100 0000 1000 1000 &cp2 + CVM_MT_KAS_ENC_CBC 010010 00101 rt:5 0100 0000 1000 1001 &cp2 + CVM_MT_3DES_ENC 010010 00101 rt:5 0100 0000 1000 1010 &cp2 + CVM_MT_KAS_ENC 010010 00101 rt:5 0100 0000 1000 1011 &cp2 + CVM_MT_3DES_DEC_CBC 010010 00101 rt:5 0100 0000 1000 1100 &cp2 + CVM_MT_3DES_DEC 010010 00101 rt:5 0100 0000 1000 1110 &cp2 CVM_MT_CRC_POLYNOMIAL 010010 00101 rt:5 0100 0010 0000 0000 &cp2 CVM_MT_CRC_POLYNOMIAL_REFLECT 010010 00101 rt:5 0100 0010 0001 0000 &cp2 CVM_MT_HSH_STARTSHA512 010010 00101 rt:5 0100 0010 0100 1111 &cp2 diff --git a/target/mips/tcg/octeon_translate.c b/target/mips/tcg/octeon_translate.c index b4663b35a3..76792c9c87 100644 --- a/target/mips/tcg/octeon_translate.c +++ b/target/mips/tcg/octeon_translate.c @@ -349,6 +349,23 @@ CP2_MT_HELPER(CVM_MT_ZUC_START, zuc_start); CP2_MT_HELPER(CVM_MT_ZUC_MORE, zuc_more); CP2_MT_HELPER(CVM_MT_SNOW3G_START, snow3g_start); CP2_MT_HELPER(CVM_MT_SNOW3G_MORE, snow3g_more); +CP2_MT_HELPER(CVM_MT_AES_ENC_CBC1, aes_enc_cbc1); +CP2_MT_HELPER(CVM_MT_AES_ENC1, aes_enc1); +CP2_MT_HELPER(CVM_MT_AES_DEC_CBC1, aes_dec_cbc1); +CP2_MT_HELPER(CVM_MT_AES_DEC1, aes_dec1); +CP2_MT_HELPER(CVM_MT_SMS4_ENC_CBC1, sms4_enc_cbc1); +CP2_MT_HELPER(CVM_MT_SMS4_ENC1, sms4_enc1); +CP2_MT_HELPER(CVM_MT_SMS4_DEC_CBC1, sms4_dec_cbc1); +CP2_MT_HELPER(CVM_MT_SMS4_DEC1, sms4_dec1); +CP2_MT_HELPER(CVM_MT_3DES_ENC_CBC, des3_enc_cbc); +CP2_MT_HELPER(CVM_MT_KAS_ENC_CBC, kas_enc_cbc); +CP2_MT_HELPER(CVM_MT_3DES_ENC, des3_enc); +CP2_MT_HELPER(CVM_MT_KAS_ENC, kas_enc); +CP2_MT_HELPER(CVM_MT_3DES_DEC_CBC, des3_dec_cbc); +CP2_MT_HELPER(CVM_MT_3DES_DEC, des3_dec); +CP2_MT_HELPER(CVM_MT_CAMELLIA_FL, camellia_fl); +CP2_MT_HELPER(CVM_MT_CAMELLIA_FLINV, camellia_flinv); +CP2_MT_HELPER(CVM_MT_CAMELLIA_ROUND, camellia_round); CP2_MT_HELPER(CVM_MT_HSH_STARTSHA1_COMPAT, hsh_startsha1_compat); CP2_MT_I64(CVM_MT_HSH_DATW0, hsh_dat[0]); CP2_MT_I64(CVM_MT_HSH_DATW1, hsh_dat[1]); From 8d399e3e037276484e44ff92ffa8f2677354bdcd Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Mon, 8 Jun 2026 12:59:44 -0600 Subject: [PATCH 19/23] target/mips: decode Octeon CHORD and LLM COP2 selectors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add explicit decodetree entries and translator bindings for the Octeon CHORD and sparse LLM COP2 selectors. CHORD and LLM use their own COP2 selector window rather than the crypto engine windows covered by the preceding decode patches. This completes the explicit COP2 selector coverage by adding the remaining CHORD and LLM register and operation selectors. Signed-off-by: James Hilliard Acked-by: Richard Henderson Message-ID: <20260608-mips-octeon-missing-insns-v2-v16-19-daef7a0d8b04@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- target/mips/tcg/octeon.decode | 13 +++++++++++++ target/mips/tcg/octeon_translate.c | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/target/mips/tcg/octeon.decode b/target/mips/tcg/octeon.decode index 4ac38d264c..a8c944e668 100644 --- a/target/mips/tcg/octeon.decode +++ b/target/mips/tcg/octeon.decode @@ -167,6 +167,9 @@ LDX 011111 ..... ..... ..... 01000 001010 @lx CVM_MF_GFM_RESINP0 010010 00001 rt:5 0000 0010 0101 1010 &cp2 CVM_MF_GFM_RESINP1 010010 00001 rt:5 0000 0010 0101 1011 &cp2 CVM_MF_GFM_POLY 010010 00001 rt:5 0000 0010 0101 1110 &cp2 + CVM_MF_CHORD 010010 00001 rt:5 0000 0100 0000 0000 &cp2 + CVM_MF_LLM_DATA0 010010 00001 rt:5 0000 0100 0000 0010 &cp2 + CVM_MF_LLM_DATA1 010010 00001 rt:5 0000 0100 0000 1010 &cp2 CVM_MT_HSH_DAT0 010010 00101 rt:5 0000 0000 0100 0000 &cp2 CVM_MT_HSH_DAT1 010010 00101 rt:5 0000 0000 0100 0001 &cp2 CVM_MT_HSH_DAT2 010010 00101 rt:5 0000 0000 0100 0010 &cp2 @@ -261,6 +264,16 @@ LDX 011111 ..... ..... ..... 01000 001010 @lx CVM_MT_SHA3_XORDAT15 010010 00101 rt:5 0000 0010 1100 1111 &cp2 CVM_MT_SHA3_XORDAT16 010010 00101 rt:5 0000 0010 1101 0000 &cp2 CVM_MT_SHA3_XORDAT17 010010 00101 rt:5 0000 0010 1101 0001 &cp2 + CVM_MT_LLM_READ_ADDR0 010010 00101 rt:5 0000 0100 0000 0000 &cp2 + CVM_MT_LLM_WRITE_ADDR0 010010 00101 rt:5 0000 0100 0000 0001 &cp2 + CVM_MT_LLM_DATA0 010010 00101 rt:5 0000 0100 0000 0010 &cp2 + CVM_MT_LLM_READ64_ADDR0 010010 00101 rt:5 0000 0100 0000 0100 &cp2 + CVM_MT_LLM_WRITE64_ADDR0 010010 00101 rt:5 0000 0100 0000 0101 &cp2 + CVM_MT_LLM_READ_ADDR1 010010 00101 rt:5 0000 0100 0000 1000 &cp2 + CVM_MT_LLM_WRITE_ADDR1 010010 00101 rt:5 0000 0100 0000 1001 &cp2 + CVM_MT_LLM_DATA1 010010 00101 rt:5 0000 0100 0000 1010 &cp2 + CVM_MT_LLM_READ64_ADDR1 010010 00101 rt:5 0000 0100 0000 1100 &cp2 + CVM_MT_LLM_WRITE64_ADDR1 010010 00101 rt:5 0000 0100 0000 1101 &cp2 CVM_MT_CRC_LEN 010010 00101 rt:5 0001 0010 0000 0010 &cp2 CVM_MT_CRC_DWORD 010010 00101 rt:5 0001 0010 0000 0111 &cp2 CVM_MT_CRC_VAR 010010 00101 rt:5 0001 0010 0000 1000 &cp2 diff --git a/target/mips/tcg/octeon_translate.c b/target/mips/tcg/octeon_translate.c index 76792c9c87..a0db6630c7 100644 --- a/target/mips/tcg/octeon_translate.c +++ b/target/mips/tcg/octeon_translate.c @@ -235,6 +235,9 @@ CP2_MF_I64(CVM_MF_GFM_MUL1, gfm_mul[1]); CP2_MF_I64(CVM_MF_GFM_RESINP0, gfm_resinp[0]); CP2_MF_I64(CVM_MF_GFM_RESINP1, gfm_resinp[1]); CP2_MF_U16(CVM_MF_GFM_POLY, gfm_poly); +CP2_MF_I64(CVM_MF_CHORD, chord); +CP2_MF_I64(CVM_MF_LLM_DATA0, llm_data[0]); +CP2_MF_I64(CVM_MF_LLM_DATA1, llm_data[1]); CP2_MF_HELPER(CVM_MF_CRC_IV_REFLECT, crc_iv_reflect); CP2_MF_I64(CVM_MF_SHA3_DAT24, sha3_dat24); @@ -306,6 +309,8 @@ CP2_MT_I64(CVM_MT_GFM_RESINP0, gfm_resinp[0]); CP2_MT_I64(CVM_MT_GFM_RESINP1, gfm_resinp[1]); CP2_MT_XOR_I64(CVM_MT_GFM_XOR0, gfm_resinp[0]); CP2_MT_U16(CVM_MT_GFM_POLY, gfm_poly); +CP2_MT_I64(CVM_MT_LLM_DATA0, llm_data[0]); +CP2_MT_I64(CVM_MT_LLM_DATA1, llm_data[1]); CP2_MT_U8_MASKED(CVM_MT_CRC_LEN, crc_len, 0xf); CP2_MT_U32(CVM_MT_CRC_POLYNOMIAL, crc_poly); @@ -395,6 +400,14 @@ CP2_MT_HELPER(CVM_MT_HSH_STARTMD5, hsh_startmd5); CP2_MT_HELPER(CVM_MT_HSH_STARTSHA256, hsh_startsha256); CP2_MT_HELPER(CVM_MT_HSH_STARTSHA, hsh_startsha); CP2_MT_HELPER(CVM_MT_HSH_STARTSHA512, hsh_startsha512); +CP2_MT_HELPER(CVM_MT_LLM_READ_ADDR0, llm_read_addr0); +CP2_MT_HELPER(CVM_MT_LLM_WRITE_ADDR0, llm_write_addr0); +CP2_MT_HELPER(CVM_MT_LLM_READ64_ADDR0, llm_read64_addr0); +CP2_MT_HELPER(CVM_MT_LLM_WRITE64_ADDR0, llm_write64_addr0); +CP2_MT_HELPER(CVM_MT_LLM_READ_ADDR1, llm_read_addr1); +CP2_MT_HELPER(CVM_MT_LLM_WRITE_ADDR1, llm_write_addr1); +CP2_MT_HELPER(CVM_MT_LLM_READ64_ADDR1, llm_read64_addr1); +CP2_MT_HELPER(CVM_MT_LLM_WRITE64_ADDR1, llm_write64_addr1); static bool trans_BBIT(DisasContext *ctx, arg_BBIT *a) { From c2fd17ec64451d3aa181623e056ca1ce019eddcd Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Mon, 8 Jun 2026 12:59:45 -0600 Subject: [PATCH 20/23] target/mips: add Octeon CvmCount RDHWR support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Octeon exposes CvmCount through RDHWR register 31. Add the Octeon-only decode path, enable the corresponding HWREna bit for linux-user, and use an unsigned mask when checking HWREna so bit 31 is handled safely. For user-mode emulation, return host ticks as a monotonic counter source suitable for existing Octeon userspace code. In system mode, fall back to the existing CP0 Count value. Reviewed-by: Richard Henderson Signed-off-by: James Hilliard Message-ID: <20260608-mips-octeon-missing-insns-v2-v16-20-daef7a0d8b04@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- target/mips/cpu.c | 1 + target/mips/helper.h | 1 + target/mips/tcg/op_helper.c | 13 ++++++++++++- target/mips/tcg/translate.c | 11 +++++++++++ tests/tcg/mips/user/isa/octeon/octeon-insns.c | 17 +++++++++++++++++ 5 files changed, 42 insertions(+), 1 deletion(-) diff --git a/target/mips/cpu.c b/target/mips/cpu.c index b223b767c9..d72044aef6 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -320,6 +320,7 @@ static void mips_cpu_reset_hold(Object *obj, ResetType type) env->CP0_HWREna |= 0x0000000F; if (env->insn_flags & INSN_OCTEON) { env->CP0_HWREna |= 0x40000000u; + env->CP0_HWREna |= 0x80000000u; } if (env->CP0_Config1 & (1 << CP0C1_FP)) { env->CP0_Status |= (1 << CP0St_CU1); diff --git a/target/mips/helper.h b/target/mips/helper.h index 141350e80a..786117813a 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -255,6 +255,7 @@ DEF_HELPER_1(rdhwr_ccres, tl, env) DEF_HELPER_1(rdhwr_performance, tl, env) DEF_HELPER_1(rdhwr_xnp, tl, env) DEF_HELPER_1(rdhwr_chord, tl, env) +DEF_HELPER_1(rdhwr_cvmcount, tl, env) DEF_HELPER_2(pmon, void, env, int) DEF_HELPER_1(wait, void, env) diff --git a/target/mips/tcg/op_helper.c b/target/mips/tcg/op_helper.c index 3e586e3049..df1b5c3734 100644 --- a/target/mips/tcg/op_helper.c +++ b/target/mips/tcg/op_helper.c @@ -25,6 +25,7 @@ #include "exec/memop.h" #include "fpu_helper.h" #include "qemu/crc32c.h" +#include "qemu/timer.h" #include static inline target_ulong bitswap(target_ulong v) @@ -209,7 +210,7 @@ target_ulong helper_yield(CPUMIPSState *env, target_ulong arg) static inline void check_hwrena(CPUMIPSState *env, int reg, uintptr_t pc) { - if ((env->hflags & MIPS_HFLAG_CP0) || (env->CP0_HWREna & (1 << reg))) { + if ((env->hflags & MIPS_HFLAG_CP0) || (env->CP0_HWREna & (1u << reg))) { return; } do_raise_exception(env, EXCP_RI, pc); @@ -261,6 +262,16 @@ target_ulong helper_rdhwr_chord(CPUMIPSState *env) return env->octeon_crypto.chord; } +target_ulong helper_rdhwr_cvmcount(CPUMIPSState *env) +{ + check_hwrena(env, 31, GETPC()); +#ifdef CONFIG_USER_ONLY + return cpu_get_host_ticks(); +#else + return (uint32_t)cpu_mips_get_count(env); +#endif +} + void helper_pmon(CPUMIPSState *env, int function) { function /= 2; diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c index 1f44932882..e3467d1525 100644 --- a/target/mips/tcg/translate.c +++ b/target/mips/tcg/translate.c @@ -10933,6 +10933,17 @@ void gen_rdhwr(DisasContext *ctx, int rt, int rd, int sel) gen_helper_rdhwr_chord(t0, tcg_env); gen_store_gpr(t0, rt); break; + case 31: + if (!(ctx->insn_flags & INSN_OCTEON)) { + gen_reserved_instruction(ctx); + break; + } + translator_io_start(&ctx->base); + gen_helper_rdhwr_cvmcount(t0, tcg_env); + gen_store_gpr(t0, rt); + gen_save_pc(ctx->base.pc_next + 4); + ctx->base.is_jmp = DISAS_EXIT; + break; default: /* Invalid */ MIPS_INVAL("rdhwr"); gen_reserved_instruction(ctx); diff --git a/tests/tcg/mips/user/isa/octeon/octeon-insns.c b/tests/tcg/mips/user/isa/octeon/octeon-insns.c index f3c52d7829..6480c8532a 100644 --- a/tests/tcg/mips/user/isa/octeon/octeon-insns.c +++ b/tests/tcg/mips/user/isa/octeon/octeon-insns.c @@ -330,6 +330,22 @@ static uint64_t octeon_cop2_gfm_mul_reflect_readback(uint64_t value) return rd; } +static uint64_t octeon_rdhwr31_non_decreasing(void) +{ + uint64_t first, second; + + asm volatile( + ".word 0x7c08f83b\n\t" /* rdhwr $8, $31 */ + ".word 0x7c09f83b\n\t" /* rdhwr $9, $31 */ + "move %[first], $8\n\t" + "move %[second], $9\n\t" + : [first] "=r" (first), [second] "=r" (second) + : + : "$8", "$9"); + + return second >= first; +} + int main(void) { assert(octeon_baddu(0x123, 0x0f0) == 0x13); @@ -358,6 +374,7 @@ int main(void) 0x0123456789abcdefULL) == 0xf7b3d591e6a2c480ULL); assert(octeon_cop2_gfm_mul_reflect_readback( 0xfedcba9876543210ULL) == 0x084c2a6e195d3b7fULL); + assert(octeon_rdhwr31_non_decreasing()); return 0; } From b6726871b94023acd4083634549d4102472d0f05 Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Mon, 8 Jun 2026 12:59:46 -0600 Subject: [PATCH 21/23] tests/tcg/mips: cover Octeon QMAC instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add smoke coverage for Octeon QMAC and QMACS fixed-point accumulator instruction paths. The coverage exercises normal accumulation, saturating accumulation, and the sticky saturation flag. Signed-off-by: James Hilliard Reviewed-by: Richard Henderson Message-ID: <20260608-mips-octeon-missing-insns-v2-v16-21-daef7a0d8b04@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- tests/tcg/mips/user/isa/octeon/octeon-insns.c | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/tcg/mips/user/isa/octeon/octeon-insns.c b/tests/tcg/mips/user/isa/octeon/octeon-insns.c index 6480c8532a..6fffc82010 100644 --- a/tests/tcg/mips/user/isa/octeon/octeon-insns.c +++ b/tests/tcg/mips/user/isa/octeon/octeon-insns.c @@ -129,6 +129,43 @@ static uint64_t octeon_vmm0(uint64_t mpl0, uint64_t p0, return rd; } +static uint64_t octeon_qmac_lo(uint64_t rs, uint64_t rt, uint64_t lo) +{ + uint64_t rd; + + asm volatile( + "move $8, %[rs]\n\t" + "move $9, %[rt]\n\t" + "mtlo %[lo]\n\t" + "mthi $0\n\t" + ".word 0x710904d2\n\t" /* qmac.03 $8, $9 */ + "mflo %[rd]\n\t" + : [rd] "=r" (rd) + : [rs] "r" (rs), [rt] "r" (rt), [lo] "r" (lo) + : "$8", "$9"); + + return rd; +} + +static uint64_t octeon_qmacs_state(uint64_t rs, uint64_t rt, uint64_t lo) +{ + uint64_t hi, rd; + + asm volatile( + "move $8, %[rs]\n\t" + "move $9, %[rt]\n\t" + "mtlo %[lo]\n\t" + "mthi $0\n\t" + ".word 0x71090012\n\t" /* qmacs.00 $8, $9 */ + "mfhi %[hi]\n\t" + "mflo %[rd]\n\t" + : [hi] "=r" (hi), [rd] "=r" (rd) + : [rs] "r" (rs), [rt] "r" (rt), [lo] "r" (lo) + : "$8", "$9"); + + return ((hi & 1) << 32) | (rd & 0xffffffff); +} + static uint64_t octeon_vmm0_zeroes_mpl1(void) { uint64_t rd; @@ -355,6 +392,9 @@ int main(void) assert(octeon_seq(0xabc, 0xdef) == 0); assert(octeon_sne(0xabc, 0xabc) == 0); assert(octeon_sne(0xabc, 0xdef) == 1); + assert(octeon_qmac_lo(0x0003000000000000ULL, 2, 1) == 13); + assert(octeon_qmacs_state(1, 1, 0x7ffffffe) == 0x17fffffffULL); + assert(octeon_qmacs_state(0x8000, 0x8000, 0) == 0x17fffffffULL); assert(octeon_vmulu(5, 7, 11) == 46); assert(octeon_vmm0(5, 13, 7, 11) == 59); assert(octeon_vmm0_zeroes_mpl1() == 0); From 614a52cf549e6aefa656634b4d3fa0d4686125c6 Mon Sep 17 00:00:00 2001 From: Randy Schifflin Date: Mon, 29 Jun 2026 14:49:13 -0700 Subject: [PATCH 22/23] target/sh4: fixup tcg for sh4 fipr/ftrv instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes TCG generation for sh4 `fipr` and `ftrv` instructions. Updates the current logic for these instructions to check the FPSCR register appropriately (according to the sh4 cpu manual, `fipr` and `ftrv` are only defined when the FPSCR register PR flag is 0). Also fixes the mth/nth-vector operands by multiplying by 4 to convert to the correct floating point register offset. Signed-off-by: Randy Schifflin Reviewed-by: Yoshinori Sato Message-ID: <20260629-fixup-sh4-tcg-fpu-instructions-b4-v1-2-4356b305f971@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- target/sh4/op_helper.c | 2 +- target/sh4/translate.c | 15 +++++---------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/target/sh4/op_helper.c b/target/sh4/op_helper.c index 90c065b217..777380f8e4 100644 --- a/target/sh4/op_helper.c +++ b/target/sh4/op_helper.c @@ -488,7 +488,7 @@ void helper_ftrv(CPUSH4State *env, uint32_t n) float32 p; bank_matrix = (env->sr & FPSCR_FR) ? 0 : 16; - bank_vector = (env->sr & FPSCR_FR) ? 16 : 0; + bank_vector = (env->sr & FPSCR_FR) ? 16 + n : n; set_float_exception_flags(0, &env->fp_status); for (i = 0 ; i < 4 ; i++) { r[i] = float32_zero; diff --git a/target/sh4/translate.c b/target/sh4/translate.c index d38a6bd352..373950fd66 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -377,11 +377,6 @@ static inline void gen_store_fpr64(DisasContext *ctx, TCGv_i64 t, int reg) goto do_illegal; \ } -#define CHECK_FPSCR_PR_1 \ - if (!(ctx->tbflags & FPSCR_PR)) { \ - goto do_illegal; \ - } - #define CHECK_SH4A \ if (!(ctx->features & SH_FEATURE_SH4A)) { \ goto do_illegal; \ @@ -1740,22 +1735,22 @@ static void _decode_opc(DisasContext * ctx) return; case 0xf0ed: /* fipr FVm,FVn */ CHECK_FPU_ENABLED - CHECK_FPSCR_PR_1 + CHECK_FPSCR_PR_0 { - TCGv m = tcg_constant_i32((ctx->opcode >> 8) & 3); - TCGv n = tcg_constant_i32((ctx->opcode >> 10) & 3); + TCGv m = tcg_constant_i32(((ctx->opcode >> 8) & 3) << 2); + TCGv n = tcg_constant_i32(((ctx->opcode >> 10) & 3) << 2); gen_helper_fipr(tcg_env, m, n); return; } break; case 0xf0fd: /* ftrv XMTRX,FVn */ CHECK_FPU_ENABLED - CHECK_FPSCR_PR_1 + CHECK_FPSCR_PR_0 { if ((ctx->opcode & 0x0300) != 0x0100) { goto do_illegal; } - TCGv n = tcg_constant_i32((ctx->opcode >> 10) & 3); + TCGv n = tcg_constant_i32(((ctx->opcode >> 10) & 3) << 2); gen_helper_ftrv(tcg_env, n); return; } From f086625548aa2f839c119243121ef863ecb606a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 7 Jul 2026 11:52:37 +0200 Subject: [PATCH 23/23] qemu-options: Do not list -enable-kvm on MIPS binaries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When removing KVM support in commit 630decdfccd we forgot to remove MIPS of the '-enable-kvm' option help. Do it now. Fixes: 630decdfccd ("buildsys: Remove MIPS KVM") Inspired-by: Miao Wang Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Message-Id: <20260707095723.36591-1-philmd@oss.qualcomm.com> --- qemu-options.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-options.hx b/qemu-options.hx index e44b47de68..ccb71743ee 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -5163,7 +5163,7 @@ ERST DEF("enable-kvm", 0, QEMU_OPTION_enable_kvm, \ "-enable-kvm enable KVM full virtualization support\n", - QEMU_ARCH_ARM | QEMU_ARCH_I386 | QEMU_ARCH_MIPS | QEMU_ARCH_PPC | + QEMU_ARCH_ARM | QEMU_ARCH_I386 | QEMU_ARCH_PPC | QEMU_ARCH_RISCV | QEMU_ARCH_S390X) SRST ``-enable-kvm``