hw/misc/aspeed_hace: Support the AES-GCM mode for the crypto command
Implement the AES-GCM mode (HACE10[6:4] = 0b101) used by the AST2700 crypto engine: decode the GCM selection, read the 96-bit IV from the context buffer, operate on the exact data length (GCM handles a partial final block itself), and write the 128-bit authentication tag to the tag buffer (HACE18/HACE8C). The hardware GCM path is only used without associated data (the driver falls back to software otherwise), so AAD is not modelled and a non-zero HACE14 is reported as unimplemented. Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com> Reviewed-by: Kane Chen <kane_chen@aspeedtech.com> Link: https://lore.kernel.org/qemu-devel/20260811060115.1849266-15-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater <clg@redhat.com>
Jamin Lin committed
Aug 11, 2026 at 06:01 UTC
7a1a61b7ace9a4f7dad5cc3d4d69459029360961
1 file changed
+62
-8
hw/misc/aspeed_hace.c
+62
-8
@@ -31,6 +31,9 @@
31
/* HACE0C[27:0] holds the crypto data length */
32
#define CRYPT_DATA_LEN_MASK 0x0FFFFFFF
33
#define R_CRYPT_CMD (0x10 / 4)
34
+/* AES-GCM associated data length (HACE14) and tag write buffer (HACE18) */
35
+#define R_CRYPT_GCM_ADD_LEN (0x14 / 4)
36
+#define R_CRYPT_GCM_TAG (0x18 / 4)
37
/* Crypto engine command register (HACE10) bits */
38
#define CRYPT_CMD_ENCRYPT BIT(7)
39
#define CRYPT_CMD_ISR_EN BIT(12)
@@ -42,6 +45,7 @@
45
#define CRYPT_CMD_ECB (0x0 << 4)
46
#define CRYPT_CMD_CBC (0x1 << 4)
47
#define CRYPT_CMD_CTR (0x4 << 4)
48
+#define CRYPT_CMD_GCM (0x5 << 4)
49
/* AES key length HACE10[3:2] */
50
#define CRYPT_CMD_AES_KEY_LEN_MASK (0x3 << 2)
51
#define CRYPT_CMD_AES256 (0x2 << 2)
@@ -57,10 +61,15 @@
61
#define CRYPT_CTX_KEY_OFFSET 0x10
62
#define CRYPT_CTX_SIZE 0x30
63
64
+/* AES-GCM uses a 96-bit IV and a 128-bit authentication tag */
65
+#define CRYPT_GCM_IV_LEN 12
66
+#define CRYPT_GCM_TAG_LEN 16
67
+
68
/* AST2700 64-bit DMA high address registers for the crypto command */
69
#define R_CRYPT_SRC_HI (0x80 / 4)
70
#define R_CRYPT_DEST_HI (0x84 / 4)
71
#define R_CRYPT_CONTEXT_HI (0x88 / 4)
72
+#define R_CRYPT_GCM_TAG_HI (0x8c / 4)
73
74
#define R_STATUS (0x1c / 4)
75
#define HASH_IRQ BIT(9)
@@ -596,6 +605,9 @@ static bool crypt_decode_cmd(uint32_t cmd, QCryptoCipherAlgo *alg,
605
case CRYPT_CMD_CTR:
606
*mode = QCRYPTO_CIPHER_MODE_CTR;
607
break;
608
+ case CRYPT_CMD_GCM:
609
+ *mode = QCRYPTO_CIPHER_MODE_GCM;
610
+ break;
611
default:
612
return false;
613
}
@@ -689,11 +701,12 @@ static uint64_t crypt_get_addr(AspeedHACEState *s, int reg, int reg_hi)
701
}
702
703
/*
692
- * Perform an AES/DES/3DES ECB/CBC operation. The source and destination are
693
- * either single contiguous buffers (direct access mode) or scatter-gather
694
- * lists (HACE10[18]/[19]), addressed by HACE00/HACE04; the IV/key come from
695
- * the context buffer (HACE08). For CBC the resulting chaining IV is written
696
- * back to the context buffer so the driver can continue the chain.
704
+ * Perform an AES/DES/3DES ECB/CBC/CTR or AES-GCM operation. The source and
705
+ * destination are either single contiguous buffers (direct access mode) or
706
+ * scatter-gather lists (HACE10[18]/[19]), addressed by HACE00/HACE04; the
707
+ * IV/key come from the context buffer (HACE08). For CBC and CTR the resulting
708
+ * chaining state is written back to the context buffer so the driver can
709
+ * continue; for GCM the authentication tag is written to the tag buffer.
710
*/
711
static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd)
712
{
@@ -703,6 +716,7 @@ static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd)
716
g_autoptr(QCryptoCipher) cipher = NULL;
717
g_autofree uint8_t *src_buf = NULL;
718
g_autofree uint8_t *dst_buf = NULL;
719
+ uint8_t tag[CRYPT_GCM_TAG_LEN];
720
uint8_t ctx[CRYPT_CTX_SIZE];
721
Error *local_err = NULL;
722
QCryptoCipherMode mode;
@@ -711,10 +725,13 @@ static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd)
725
uint64_t ctx_addr;
726
uint64_t src_addr;
727
uint64_t dst_addr;
728
+ uint64_t tag_addr;
729
+ uint32_t aad_len;
730
size_t iv_offset;
731
size_t blocklen;
732
size_t buf_len;
733
size_t keylen;
734
+ size_t ivlen;
735
bool status;
736
737
if (len == 0) {
@@ -734,6 +751,20 @@ static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd)
751
return;
752
}
753
754
+ /* GCM uses a 96-bit IV; the block modes use a full-block IV. */
755
+ ivlen = (mode == QCRYPTO_CIPHER_MODE_GCM) ? CRYPT_GCM_IV_LEN : blocklen;
756
+
757
+ /*
758
+ * The hardware GCM path is only exercised without associated data (the
759
+ * driver falls back to software when there is any), so AAD is not modelled.
760
+ */
761
+ aad_len = s->regs[R_CRYPT_GCM_ADD_LEN];
762
+ if (mode == QCRYPTO_CIPHER_MODE_GCM && aad_len != 0) {
763
+ qemu_log_mask(LOG_UNIMP,
764
+ "%s: GCM associated data is not implemented\n", __func__);
765
+ return;
766
+ }
767
+
768
/* Fetch the IV and key from the context buffer in DRAM. */
769
ctx_addr = crypt_get_addr(s, R_CRYPT_CONTEXT, R_CRYPT_CONTEXT_HI);
770
if (address_space_read(&s->dram_as, ctx_addr, MEMTXATTRS_UNSPECIFIED,
@@ -758,7 +789,7 @@ static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd)
789
}
790
791
if (mode != QCRYPTO_CIPHER_MODE_ECB &&
761
- qcrypto_cipher_setiv(cipher, ctx + iv_offset, blocklen,
792
+ qcrypto_cipher_setiv(cipher, ctx + iv_offset, ivlen,
793
&local_err) < 0) {
794
qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto cipher setiv failed: %s\n",
795
__func__, error_get_pretty(local_err));
@@ -769,9 +800,11 @@ static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd)
800
/*
801
* Round the working buffers up to a whole block. Block modes are already
802
* block-aligned; the stream-like CTR mode may leave a partial final block
772
- * that the engine still processes a full block at a time.
803
+ * that the engine still processes a full block at a time. GCM handles a
804
+ * partial final block itself, so it operates on the exact length.
805
*/
774
- buf_len = QEMU_ALIGN_UP(len, blocklen);
806
+ buf_len = (mode == QCRYPTO_CIPHER_MODE_GCM) ?
807
+ len : QEMU_ALIGN_UP(len, blocklen);
808
src_buf = g_malloc0(buf_len);
809
dst_buf = g_malloc0(buf_len);
810
@@ -855,6 +888,24 @@ static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd)
888
"%s: Failed to write IV, addr=0x%" HWADDR_PRIx "\n",
889
__func__, ctx_addr + iv_offset);
890
}
891
+ } else if (mode == QCRYPTO_CIPHER_MODE_GCM) {
892
+ /*
893
+ * GCM authenticates the message and writes the resulting tag to the
894
+ * dedicated tag buffer (HACE18/HACE8C).
895
+ */
896
+ if (qcrypto_cipher_gettag(cipher, tag, sizeof(tag), &local_err) < 0) {
897
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto cipher gettag failed: "
898
+ "%s\n", __func__, error_get_pretty(local_err));
899
+ error_free(local_err);
900
+ return;
901
+ }
902
+ tag_addr = crypt_get_addr(s, R_CRYPT_GCM_TAG, R_CRYPT_GCM_TAG_HI);
903
+ if (address_space_write(&s->dram_as, tag_addr, MEMTXATTRS_UNSPECIFIED,
904
+ tag, sizeof(tag))) {
905
+ qemu_log_mask(LOG_GUEST_ERROR,
906
+ "%s: Failed to write tag, addr=0x%" HWADDR_PRIx "\n",
907
+ __func__, tag_addr);
908
+ }
909
}
910
}
911
@@ -899,9 +950,11 @@ static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data,
950
case R_CRYPT_SRC:
951
case R_CRYPT_DEST:
952
case R_CRYPT_CONTEXT:
953
+ case R_CRYPT_GCM_TAG:
954
data &= ahc->src_mask;
955
break;
956
case R_CRYPT_DATA_LEN:
957
+ case R_CRYPT_GCM_ADD_LEN:
958
data &= CRYPT_DATA_LEN_MASK;
959
break;
960
case R_HASH_SRC:
@@ -980,6 +1033,7 @@ static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data,
1033
data &= ahc->src_hi_mask;
1034
break;
1035
case R_CRYPT_DEST_HI:
1036
+ case R_CRYPT_GCM_TAG_HI:
1037
data &= ahc->dest_hi_mask;
1038
break;
1039
case R_CRYPT_CONTEXT_HI: