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


Reply via email to