@samitouri / QOSamiQemu / commits / 0375f6498e

tests/qtest/aspeed-hace: Test the crypto command on the AST2700

Cover the AST2700 crypto engine, which drives 64-bit scatter-gather DMA and adds AES-GCM on top of the ECB/CBC/CTR modes shared with the AST2600. Add AES-128 and AES-256 GCM known-answer vectors (GCM specification / NIST SP 800-38D, no associated data) and a dedicated GCM runner that programs the tag buffer and reads the tag back, checking it after both encryption and decryption. Register the AST2700 with all four modes. 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-17-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater <clg@redhat.com>

Jamin Lin committed Aug 11, 2026 at 06:01 UTC 0375f6498eee6188089924bb766c653492ff8857
3 files changed +172 -1
tests/qtest/aspeed-hace-utils.c
+162 -1
@@ -654,6 +654,8 @@ void aspeed_test_addresses(const char *machine, const uint32_t base,
654 #define HACE_CRYPTO_CONTEXT 0x08
655 #define HACE_CRYPTO_DATA_LEN 0x0c
656 #define HACE_CRYPTO_CMD 0x10
657 +#define HACE_CRYPTO_GCM_ADD_LEN 0x14
658 +#define HACE_CRYPTO_GCM_TAG 0x18
659
660 /* Crypto command bits */
661 #define HACE_CMD_ENCRYPT BIT(7)
@@ -666,7 +668,9 @@ void aspeed_test_addresses(const char *machine, const uint32_t base,
668 #define HACE_CMD_ECB (0x0 << 4)
669 #define HACE_CMD_CBC (0x1 << 4)
670 #define HACE_CMD_CTR (0x4 << 4)
671 +#define HACE_CMD_GCM (0x5 << 4)
672 #define HACE_CMD_AES128 (0x0 << 2)
673 +#define HACE_CMD_AES256 (0x2 << 2)
674
675 /* Context buffer layout: IV (DES at +8), key at +0x10 */
676 #define HACE_CTX_KEY_OFFSET 0x10
@@ -794,6 +798,59 @@ static const uint8_t tdes_ctr_ctext[8] = {
798 static const uint8_t tdes_ctr_ivout[8] = {
799 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
800
801 +/*
802 + * aes_gcm_tv_template[2] (AES-128) and [9] (AES-256), from the McGrew & Viega
803 + * GCM spec (also NIST SP 800-38D), no AAD. Both cases share this plaintext/IV.
804 + */
805 +static const uint8_t aes_gcm_ptext[64] = {
806 + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
807 + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
808 + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
809 + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
810 + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
811 + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
812 + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
813 + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 };
814 +static const uint8_t aes_gcm_iv[12] = {
815 + 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
816 + 0xde, 0xca, 0xf8, 0x88 };
817 +
818 +/* aes_gcm_tv_template[2] (AES-128) */
819 +static const uint8_t aes128_gcm_key[16] = {
820 + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
821 + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 };
822 +static const uint8_t aes128_gcm_ctext[64] = {
823 + 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24,
824 + 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c,
825 + 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0,
826 + 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e,
827 + 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c,
828 + 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05,
829 + 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
830 + 0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85 };
831 +static const uint8_t aes128_gcm_tag[16] = {
832 + 0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6,
833 + 0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4 };
834 +
835 +/* aes_gcm_tv_template[9] (AES-256) */
836 +static const uint8_t aes256_gcm_key[32] = {
837 + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
838 + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
839 + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
840 + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 };
841 +static const uint8_t aes256_gcm_ctext[64] = {
842 + 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07,
843 + 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d,
844 + 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9,
845 + 0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa,
846 + 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d,
847 + 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38,
848 + 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
849 + 0xbc, 0xc9, 0xf6, 0x62, 0x89, 0x80, 0x15, 0xad };
850 +static const uint8_t aes256_gcm_tag[16] = {
851 + 0xb0, 0x94, 0xda, 0xc5, 0xd9, 0x34, 0x71, 0xbd,
852 + 0xec, 0x1a, 0x50, 0x22, 0x70, 0xe3, 0xcc, 0x6c };
853 +
854 typedef struct CryptTest {
855 QCryptoCipherMode mode;
856 QCryptoCipherAlgo alg;
@@ -801,10 +858,13 @@ typedef struct CryptTest {
858 const uint8_t *iv_out;
859 const uint8_t *ptext;
860 const uint8_t *ctext;
861 + /* expected GCM authentication tag, or NULL for non-AEAD modes */
862 + const uint8_t *tag;
863 const uint8_t *key;
864 const uint8_t *iv;
865 const char *name;
866 size_t keylen;
867 + size_t taglen;
868 /* algorithm | mode | key size selection */
869 uint32_t cmd;
870 size_t ivlen;
@@ -927,6 +987,36 @@ static const CryptTest crypt_tests[] = {
987 .iv_out = tdes_ctr_ivout,
988 .len = sizeof(tdes_ctr_ptext),
989 },
990 + {
991 + .name = "aes128-gcm",
992 + .cmd = HACE_CMD_AES128 | HACE_CMD_GCM,
993 + .alg = QCRYPTO_CIPHER_ALGO_AES_128,
994 + .mode = QCRYPTO_CIPHER_MODE_GCM,
995 + .key = aes128_gcm_key,
996 + .keylen = sizeof(aes128_gcm_key),
997 + .iv = aes_gcm_iv,
998 + .ivlen = sizeof(aes_gcm_iv),
999 + .ptext = aes_gcm_ptext,
1000 + .ctext = aes128_gcm_ctext,
1001 + .tag = aes128_gcm_tag,
1002 + .taglen = sizeof(aes128_gcm_tag),
1003 + .len = sizeof(aes_gcm_ptext),
1004 + },
1005 + {
1006 + .name = "aes256-gcm",
1007 + .cmd = HACE_CMD_AES256 | HACE_CMD_GCM,
1008 + .alg = QCRYPTO_CIPHER_ALGO_AES_256,
1009 + .mode = QCRYPTO_CIPHER_MODE_GCM,
1010 + .key = aes256_gcm_key,
1011 + .keylen = sizeof(aes256_gcm_key),
1012 + .iv = aes_gcm_iv,
1013 + .ivlen = sizeof(aes_gcm_iv),
1014 + .ptext = aes_gcm_ptext,
1015 + .ctext = aes256_gcm_ctext,
1016 + .tag = aes256_gcm_tag,
1017 + .taglen = sizeof(aes256_gcm_tag),
1018 + .len = sizeof(aes_gcm_ptext),
1019 + },
1020 };
1021
1022 /* DRAM offsets for the crypto test source, destination and context buffers. */
@@ -944,6 +1034,8 @@ static const CryptTest crypt_tests[] = {
1034 */
1035 #define CRYPT_SG_FRAGS 3
1036 #define CRYPT_SG_FRAG_STRIDE 0x1000
1037 +/* DRAM offset for the AES-GCM authentication tag write buffer. */
1038 +#define CRYPT_OFF_TAG 0x60000
1039
1040 /* Describes one registered crypto test (qtest_add_data_func() data pointer). */
1041 typedef struct AspeedCryptoTest {
@@ -964,6 +1056,8 @@ static uint32_t crypt_mode_flag(uint32_t cmd)
1056 return CRYPT_MODE_CBC;
1057 case HACE_CMD_CTR:
1058 return CRYPT_MODE_CTR;
1059 + case HACE_CMD_GCM:
1060 + return CRYPT_MODE_GCM;
1061 default:
1062 return 0;
1063 }
@@ -1109,6 +1203,47 @@ static void crypt_run_sg(QTestState *s, uint32_t base, uint64_t dram,
1203 crypt_gather_sg(s, dram, CRYPT_OFF_DST, out, t->len);
1204 }
1205
1206 +/*
1207 + * Run one AES-GCM operation in scatter-gather mode: like crypt_run_sg() but
1208 + * also program the tag write buffer (HACE18) with no associated data, and read
1209 + * the authentication tag back into @out_tag.
1210 + */
1211 +static void crypt_run_gcm(QTestState *s, uint32_t base, uint64_t dram,
1212 + const CryptTest *t, bool encrypt, uint8_t *out,
1213 + uint8_t *out_tag)
1214 +{
1215 + const uint8_t *in = encrypt ? t->ptext : t->ctext;
1216 + uint64_t src_sg = dram + CRYPT_OFF_SRC_SG;
1217 + uint64_t dst_sg = dram + CRYPT_OFF_DST_SG;
1218 + uint64_t ctx = dram + CRYPT_OFF_CTX;
1219 + uint32_t cmd = t->cmd | HACE_CMD_ISR_EN | HACE_CMD_SRC_SG_CTRL |
1220 + HACE_CMD_DST_SG_CTRL;
1221 +
1222 + if (encrypt) {
1223 + cmd |= HACE_CMD_ENCRYPT;
1224 + }
1225 +
1226 + crypt_write_ctx(s, ctx, t);
1227 + crypt_make_sg(s, dram, CRYPT_OFF_SRC, src_sg, in, t->len);
1228 + crypt_make_sg(s, dram, CRYPT_OFF_DST, dst_sg, NULL, t->len);
1229 +
1230 + qtest_writel(s, base + HACE_CRYPTO_SRC, (uint32_t)src_sg);
1231 + qtest_writel(s, base + HACE_CRYPTO_DEST, (uint32_t)dst_sg);
1232 + qtest_writel(s, base + HACE_CRYPTO_CONTEXT, (uint32_t)ctx);
1233 + qtest_writel(s, base + HACE_CRYPTO_DATA_LEN, t->len);
1234 + qtest_writel(s, base + HACE_CRYPTO_GCM_ADD_LEN, 0);
1235 + qtest_writel(s, base + HACE_CRYPTO_GCM_TAG,
1236 + (uint32_t)(dram + CRYPT_OFF_TAG));
1237 + qtest_writel(s, base + HACE_CRYPTO_CMD, cmd);
1238 +
1239 + g_assert_cmphex(qtest_readl(s, base + HACE_STS) & HACE_CRYPTO_ISR, ==,
1240 + HACE_CRYPTO_ISR);
1241 + qtest_writel(s, base + HACE_STS, HACE_CRYPTO_ISR);
1242 +
1243 + crypt_gather_sg(s, dram, CRYPT_OFF_DST, out, t->len);
1244 + qtest_memread(s, dram + CRYPT_OFF_TAG, out_tag, t->taglen);
1245 +}
1246 +
1247 static void aspeed_test_crypto(const void *data)
1248 {
1249 const AspeedCryptoTest *c = data;
@@ -1145,6 +1280,29 @@ static void aspeed_test_crypto(const void *data)
1280 qtest_quit(s);
1281 }
1282
1283 +static void aspeed_test_crypto_gcm(const void *data)
1284 +{
1285 + const AspeedCryptoTest *c = data;
1286 + const CryptTest *t = &crypt_tests[c->index];
1287 + QTestState *s = qtest_init(c->machine);
1288 + uint8_t out[64];
1289 + uint8_t tag[16];
1290 +
1291 + g_assert_cmpuint(t->len, <=, sizeof(out));
1292 +
1293 + /* Encrypt: ptext -> ctext, then check the authentication tag. */
1294 + crypt_run_gcm(s, c->base, c->dram, t, true, out, tag);
1295 + g_assert_cmpmem(out, t->len, t->ctext, t->len);
1296 + g_assert_cmpmem(tag, t->taglen, t->tag, t->taglen);
1297 +
1298 + /* Decrypt: ctext -> ptext, the recomputed tag must match. */
1299 + crypt_run_gcm(s, c->base, c->dram, t, false, out, tag);
1300 + g_assert_cmpmem(out, t->len, t->ptext, t->len);
1301 + g_assert_cmpmem(tag, t->taglen, t->tag, t->taglen);
1302 +
1303 + qtest_quit(s);
1304 +}
1305 +
1306 void aspeed_add_crypto_tests(const char *prefix, const char *machine,
1307 uint32_t base, uint64_t dram, uint32_t modes,
1308 bool sg)
@@ -1152,6 +1310,7 @@ void aspeed_add_crypto_tests(const char *prefix, const char *machine,
1310 int i;
1311
1312 for (i = 0; i < ARRAY_SIZE(crypt_tests); i++) {
1313 + bool is_gcm = crypt_tests[i].mode == QCRYPTO_CIPHER_MODE_GCM;
1314 g_autofree char *path = NULL;
1315 AspeedCryptoTest *t;
1316
@@ -1173,7 +1332,9 @@ void aspeed_add_crypto_tests(const char *prefix, const char *machine,
1332 t->dram = dram;
1333 t->index = i;
1334 t->sg = sg;
1176 - qtest_add_data_func_full(path, t, aspeed_test_crypto, g_free);
1335 + qtest_add_data_func_full(path, t,
1336 + is_gcm ? aspeed_test_crypto_gcm :
1337 + aspeed_test_crypto, g_free);
1338 }
1339 }
1340
tests/qtest/aspeed-hace-utils.h
+1
@@ -86,6 +86,7 @@ enum {
86 CRYPT_MODE_ECB = 1 << 0,
87 CRYPT_MODE_CBC = 1 << 1,
88 CRYPT_MODE_CTR = 1 << 2,
89 + CRYPT_MODE_GCM = 1 << 3,
90 };
91
92 /*
tests/qtest/ast2700-hace-test.c
+9
@@ -94,5 +94,14 @@ int main(int argc, char **argv)
94 qtest_add_func("ast2700/hace/sha384_accum", test_sha384_accum_ast2700);
95 qtest_add_func("ast2700/hace/sha256_accum", test_sha256_accum_ast2700);
96
97 + /*
98 + * The AST2700 crypto engine uses scatter-gather with 64-bit DMA and adds
99 + * AES-GCM on top of the ECB/CBC/CTR modes shared with the AST2600.
100 + */
101 + aspeed_add_crypto_tests("ast2700", "-machine ast2700-evb", 0x12070000,
102 + 0x400000000,
103 + CRYPT_MODE_ECB | CRYPT_MODE_CBC | CRYPT_MODE_CTR |
104 + CRYPT_MODE_GCM, true);
105 +
106 return g_test_run();
107 }