Implement the CRC32C instruction according to OSA (Oracle SPARC Architecture) 2011 section 7.19.
Using QEMU's crc32c.h and bswap.h. Gated behind the crypto CPU feature and disabled for sparc32. Signed-off-by: Stian Halseth <[email protected]> --- target/sparc/crypto_helper.c | 20 ++++++++++++++++++++ target/sparc/helper.h | 1 + target/sparc/insns.decode | 1 + target/sparc/translate.c | 2 ++ 4 files changed, 24 insertions(+) diff --git a/target/sparc/crypto_helper.c b/target/sparc/crypto_helper.c index 5d2940b825..fdae71a06f 100644 --- a/target/sparc/crypto_helper.c +++ b/target/sparc/crypto_helper.c @@ -10,6 +10,8 @@ #include "exec/helper-proto.h" #include "crypto/aes-round.h" #include "crypto/aes.h" +#include "qemu/bswap.h" +#include "qemu/crc32c.h" /* * SPARC four-operand AES round (Section 7.3). @@ -141,3 +143,21 @@ uint64_t helper_aes_kexpand2(uint64_t rs1, uint64_t rs2) { return aes_kexpand(rs1, (uint32_t)rs2); } + +/* + * CRC32C Operation 3 operand (Section 7.19) + * Accumulate CRC32C over the eight bytes of rs2, most significant first. + */ +uint64_t helper_crc32c(uint64_t rs1, uint64_t rs2) +{ + uint8_t buf[8]; + /* IV and result are byte-swapped in the register. */ + uint32_t crc = bswap32((uint32_t)rs1); + + stq_be_p(buf, rs2); + + /* Undo crc32c()'s final inversion for the instruction's raw result. */ + crc = crc32c(crc, buf, sizeof(buf)) ^ UINT32_MAX; + + return bswap32(crc); +} diff --git a/target/sparc/helper.h b/target/sparc/helper.h index 685b89d9c5..1320f5ebba 100644 --- a/target/sparc/helper.h +++ b/target/sparc/helper.h @@ -133,6 +133,7 @@ DEF_HELPER_FLAGS_3(aes_dround23_l, TCG_CALL_NO_RWG_SE, i64, i64, i64, i64) DEF_HELPER_FLAGS_2(aes_kexpand0, TCG_CALL_NO_RWG_SE, i64, i64, i64) DEF_HELPER_FLAGS_3(aes_kexpand1, TCG_CALL_NO_RWG_SE, i64, i64, i64, i32) DEF_HELPER_FLAGS_2(aes_kexpand2, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(crc32c, TCG_CALL_NO_RWG_SE, i64, i64, i64) #define VIS_CMPHELPER(name) \ DEF_HELPER_FLAGS_2(f##name##8, TCG_CALL_NO_RWG_SE, \ i64, i64, i64) \ diff --git a/target/sparc/insns.decode b/target/sparc/insns.decode index 96791c7658..05c1e73d7f 100644 --- a/target/sparc/insns.decode +++ b/target/sparc/insns.decode @@ -577,6 +577,7 @@ FCMPEq 10 000 cc:2 110101 ..... 0 0101 0111 ..... \ FPMAXU32 10 ..... 110110 ..... 1 0101 1111 ..... @d_d_d AES_KEXPAND0 10 ..... 110110 ..... 1 0011 0000 ..... @d_d_d AES_KEXPAND2 10 ..... 110110 ..... 1 0011 0001 ..... @d_d_d + CRC32C 10 ..... 110110 ..... 1 0100 0111 ..... @d_d_d FLCMPs 10 000 cc:2 110110 rs1:5 1 0101 0001 rs2:5 FLCMPd 10 000 cc:2 110110 ..... 1 0101 0010 ..... \ diff --git a/target/sparc/translate.c b/target/sparc/translate.c index 8cb405c8bd..437e4a56cb 100644 --- a/target/sparc/translate.c +++ b/target/sparc/translate.c @@ -111,6 +111,7 @@ # define gen_helper_aes_dround23_l ({ qemu_build_not_reached(); NULL; }) # define gen_helper_aes_kexpand0 ({ qemu_build_not_reached(); NULL; }) # define gen_helper_aes_kexpand2 ({ qemu_build_not_reached(); NULL; }) +# define gen_helper_crc32c ({ qemu_build_not_reached(); NULL; }) #endif #define DISAS_EXIT DISAS_TARGET_0 @@ -5439,6 +5440,7 @@ TRANS(AES_DROUND01_L, CRYPTO, do_dddd, a, gen_helper_aes_dround01_l) TRANS(AES_DROUND23_L, CRYPTO, do_dddd, a, gen_helper_aes_dround23_l) TRANS(AES_KEXPAND0, CRYPTO, do_ddd, a, gen_helper_aes_kexpand0) TRANS(AES_KEXPAND2, CRYPTO, do_ddd, a, gen_helper_aes_kexpand2) +TRANS(CRC32C, CRYPTO, do_ddd, a, gen_helper_crc32c) /* AES key expansion with RCON selected by the 5-bit immediate in imm */ static bool trans_AES_KEXPAND1(DisasContext *dc, arg_r_r_i_r *a) -- 2.43.0
