@samitouri / QOSamiQemu / commits / 48274cdb83

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

Extend the crypto known-answer tests to cover the AST2600 crypto engine, which drives the source and destination through scatter-gather lists and adds CTR mode on top of the ECB/CBC modes shared with the AST2500. Add a scatter-gather runner that describes each buffer with three non-adjacent fragments to exercise the gather/scatter path, add AES/DES/3DES CTR vectors (verifying the counter written back to the context buffer), and give aspeed_add_crypto_tests() a mode mask and a scatter-gather flag so each SoC registers exactly the modes and transfer method it supports. Register the AST2600 with ECB/CBC/CTR in scatter-gather mode. 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-6-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater <clg@redhat.com>

Jamin Lin committed Aug 11, 2026 at 06:01 UTC 48274cdb830f30bc573e089b94d0a061d7235081
3 files changed +224 -8
tests/qtest/aspeed-hace-utils.c
+212 -5
@@ -665,6 +665,7 @@ void aspeed_test_addresses(const char *machine, const uint32_t base,
665 #define HACE_CMD_OP_MODE_MASK (0x7 << 4)
666 #define HACE_CMD_ECB (0x0 << 4)
667 #define HACE_CMD_CBC (0x1 << 4)
668 +#define HACE_CMD_CTR (0x4 << 4)
669 #define HACE_CMD_AES128 (0x0 << 2)
670
671 /* Context buffer layout: IV (DES at +8), key at +0x10 */
@@ -750,6 +751,49 @@ static const uint8_t tdes_cbc_ptext[8] = {
751 static const uint8_t tdes_cbc_ctext[8] = {
752 0x0e, 0x2d, 0xb6, 0x97, 0x3c, 0x56, 0x33, 0xf4 };
753
754 +/* aes_ctr_tv_template[0] (NIST SP800-38A F.5.1), first block */
755 +static const uint8_t aes128_ctr_key[16] = {
756 + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
757 + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c };
758 +static const uint8_t aes128_ctr_iv[16] = {
759 + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
760 + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff };
761 +static const uint8_t aes128_ctr_ptext[16] = {
762 + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
763 + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a };
764 +static const uint8_t aes128_ctr_ctext[16] = {
765 + 0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26,
766 + 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce };
767 +static const uint8_t aes128_ctr_ivout[16] = {
768 + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
769 + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xff, 0x00 };
770 +
771 +/* des_ctr_tv_template[0] (Crypto++), first block */
772 +static const uint8_t des_ctr_key[8] = {
773 + 0xc9, 0x83, 0xa6, 0xc9, 0xec, 0x0f, 0x32, 0x55 };
774 +static const uint8_t des_ctr_iv[8] = {
775 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd };
776 +static const uint8_t des_ctr_ptext[8] = {
777 + 0x50, 0xb9, 0x22, 0xae, 0x17, 0x80, 0x0c, 0x75 };
778 +static const uint8_t des_ctr_ctext[8] = {
779 + 0x2f, 0x96, 0x06, 0x0f, 0x50, 0xc9, 0x68, 0x03 };
780 +static const uint8_t des_ctr_ivout[8] = {
781 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe };
782 +
783 +/* des3_ede_ctr_tv_template[0] (Crypto++), first block */
784 +static const uint8_t tdes_ctr_key[24] = {
785 + 0x9c, 0xd6, 0xf3, 0x9c, 0xb9, 0x5a, 0x67, 0x00,
786 + 0x5a, 0x67, 0x00, 0x2d, 0xce, 0xeb, 0x2d, 0xce,
787 + 0xeb, 0xb4, 0x51, 0x72, 0xb4, 0x51, 0x72, 0x1f };
788 +static const uint8_t tdes_ctr_iv[8] = {
789 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
790 +static const uint8_t tdes_ctr_ptext[8] = {
791 + 0x05, 0xec, 0x77, 0xfb, 0x42, 0xd5, 0x59, 0x20 };
792 +static const uint8_t tdes_ctr_ctext[8] = {
793 + 0x07, 0xc2, 0x08, 0x20, 0x72, 0x1f, 0x49, 0xef };
794 +static const uint8_t tdes_ctr_ivout[8] = {
795 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
796 +
797 typedef struct CryptTest {
798 QCryptoCipherMode mode;
799 QCryptoCipherAlgo alg;
@@ -841,12 +885,65 @@ static const CryptTest crypt_tests[] = {
885 .ctext = tdes_cbc_ctext,
886 .len = sizeof(tdes_cbc_ptext),
887 },
888 + {
889 + .name = "aes128-ctr",
890 + .cmd = HACE_CMD_AES128 | HACE_CMD_CTR,
891 + .alg = QCRYPTO_CIPHER_ALGO_AES_128,
892 + .mode = QCRYPTO_CIPHER_MODE_CTR,
893 + .key = aes128_ctr_key,
894 + .keylen = sizeof(aes128_ctr_key),
895 + .iv = aes128_ctr_iv,
896 + .ivlen = sizeof(aes128_ctr_iv),
897 + .ptext = aes128_ctr_ptext,
898 + .ctext = aes128_ctr_ctext,
899 + .iv_out = aes128_ctr_ivout,
900 + .len = sizeof(aes128_ctr_ptext),
901 + },
902 + {
903 + .name = "des-ctr",
904 + .cmd = HACE_CMD_DES_SELECT | HACE_CMD_CTR,
905 + .alg = QCRYPTO_CIPHER_ALGO_DES,
906 + .mode = QCRYPTO_CIPHER_MODE_CTR,
907 + .key = des_ctr_key,
908 + .keylen = sizeof(des_ctr_key),
909 + .iv = des_ctr_iv,
910 + .ivlen = sizeof(des_ctr_iv),
911 + .ptext = des_ctr_ptext,
912 + .ctext = des_ctr_ctext,
913 + .iv_out = des_ctr_ivout,
914 + .len = sizeof(des_ctr_ptext),
915 + },
916 + {
917 + .name = "des3_ede-ctr",
918 + .cmd = HACE_CMD_DES_SELECT | HACE_CMD_TRIPLE_DES | HACE_CMD_CTR,
919 + .alg = QCRYPTO_CIPHER_ALGO_3DES,
920 + .mode = QCRYPTO_CIPHER_MODE_CTR,
921 + .key = tdes_ctr_key,
922 + .keylen = sizeof(tdes_ctr_key),
923 + .iv = tdes_ctr_iv,
924 + .ivlen = sizeof(tdes_ctr_iv),
925 + .ptext = tdes_ctr_ptext,
926 + .ctext = tdes_ctr_ctext,
927 + .iv_out = tdes_ctr_ivout,
928 + .len = sizeof(tdes_ctr_ptext),
929 + },
930 };
931
932 /* DRAM offsets for the crypto test source, destination and context buffers. */
933 #define CRYPT_OFF_SRC 0x10000
934 #define CRYPT_OFF_DST 0x20000
935 #define CRYPT_OFF_CTX 0x30000
936 +/* Scatter-gather list offsets (each list has CRYPT_SG_FRAGS entries). */
937 +#define CRYPT_OFF_SRC_SG 0x40000
938 +#define CRYPT_OFF_DST_SG 0x50000
939 +/*
940 + * The scatter-gather tests split each buffer into CRYPT_SG_FRAGS fragments,
941 + * each placed CRYPT_SG_FRAG_STRIDE apart so the fragments never abut. The gaps
942 + * make the test fail if the engine ignores the list and reads one contiguous
943 + * block.
944 + */
945 +#define CRYPT_SG_FRAGS 3
946 +#define CRYPT_SG_FRAG_STRIDE 0x1000
947
948 /* Describes one registered crypto test (qtest_add_data_func() data pointer). */
949 typedef struct AspeedCryptoTest {
@@ -854,6 +951,7 @@ typedef struct AspeedCryptoTest {
951 uint64_t dram;
952 uint32_t base;
953 int index;
954 + bool sg;
955 } AspeedCryptoTest;
956
957 /* Map a command's operation mode (HACE10[6:4]) to a CRYPT_MODE_* flag. */
@@ -864,6 +962,8 @@ static uint32_t crypt_mode_flag(uint32_t cmd)
962 return CRYPT_MODE_ECB;
963 case HACE_CMD_CBC:
964 return CRYPT_MODE_CBC;
965 + case HACE_CMD_CTR:
966 + return CRYPT_MODE_CTR;
967 default:
968 return 0;
969 }
@@ -912,7 +1012,104 @@ static void crypt_run_direct(QTestState *s, uint32_t base, uint64_t dram,
1012 qtest_memread(s, dst, out, t->len);
1013 }
1014
915 -static void aspeed_test_crypto_direct(const void *data)
1015 +/*
1016 + * Byte range [*frag_off, *frag_off + *frag_len) of fragment @index when an
1017 + * @len-byte buffer is split into CRYPT_SG_FRAGS pieces; the last piece takes
1018 + * the remainder of an uneven split.
1019 + */
1020 +static void crypt_frag_range(uint32_t len, int index,
1021 + uint32_t *frag_off, uint32_t *frag_len)
1022 +{
1023 + uint32_t base = len / CRYPT_SG_FRAGS;
1024 +
1025 + *frag_off = base * index;
1026 + *frag_len = (index == CRYPT_SG_FRAGS - 1) ? len - *frag_off : base;
1027 +}
1028 +
1029 +/*
1030 + * Scatter [in, len) across CRYPT_SG_FRAGS buffers based at @base_off and spaced
1031 + * CRYPT_SG_FRAG_STRIDE apart, then build the SG list describing them at @list.
1032 + * When @in is NULL only the list is built (used for the destination, which the
1033 + * engine fills in).
1034 + */
1035 +static void crypt_make_sg(QTestState *s, uint64_t dram, uint32_t base_off,
1036 + uint64_t list, const uint8_t *in, uint32_t len)
1037 +{
1038 + struct AspeedSgList sg[CRYPT_SG_FRAGS];
1039 + uint32_t frag_off;
1040 + uint32_t frag_len;
1041 + uint64_t buf;
1042 + int i;
1043 +
1044 + for (i = 0; i < CRYPT_SG_FRAGS; i++) {
1045 + crypt_frag_range(len, i, &frag_off, &frag_len);
1046 + buf = dram + base_off + i * CRYPT_SG_FRAG_STRIDE;
1047 +
1048 + if (in) {
1049 + qtest_memwrite(s, buf, in + frag_off, frag_len);
1050 + }
1051 + sg[i].len = cpu_to_le32(frag_len | (i == CRYPT_SG_FRAGS - 1 ?
1052 + SG_LIST_LEN_LAST : 0));
1053 + sg[i].addr = cpu_to_le32((uint32_t)buf);
1054 + }
1055 +
1056 + qtest_memwrite(s, list, sg, sizeof(sg));
1057 +}
1058 +
1059 +/* Gather a scatter-gathered result back from the CRYPT_SG_FRAGS buffers. */
1060 +static void crypt_gather_sg(QTestState *s, uint64_t dram, uint32_t base_off,
1061 + uint8_t *out, uint32_t len)
1062 +{
1063 + uint32_t frag_off;
1064 + uint32_t frag_len;
1065 + int i;
1066 +
1067 + for (i = 0; i < CRYPT_SG_FRAGS; i++) {
1068 + crypt_frag_range(len, i, &frag_off, &frag_len);
1069 + qtest_memread(s, dram + base_off + i * CRYPT_SG_FRAG_STRIDE,
1070 + out + frag_off, frag_len);
1071 + }
1072 +}
1073 +
1074 +/*
1075 + * Run one block-cipher (ECB/CBC/CTR) operation in scatter-gather mode and read
1076 + * back the result. The source and destination are each split across
1077 + * CRYPT_SG_FRAGS non-adjacent DRAM buffers described by an SG list; the gaps
1078 + * ensure the test fails if the engine ignores the list and reads one
1079 + * contiguous block.
1080 + */
1081 +static void crypt_run_sg(QTestState *s, uint32_t base, uint64_t dram,
1082 + const CryptTest *t, bool encrypt, uint8_t *out)
1083 +{
1084 + const uint8_t *in = encrypt ? t->ptext : t->ctext;
1085 + uint64_t src_sg = dram + CRYPT_OFF_SRC_SG;
1086 + uint64_t dst_sg = dram + CRYPT_OFF_DST_SG;
1087 + uint64_t ctx = dram + CRYPT_OFF_CTX;
1088 + uint32_t cmd = t->cmd | HACE_CMD_ISR_EN | HACE_CMD_SRC_SG_CTRL |
1089 + HACE_CMD_DST_SG_CTRL;
1090 +
1091 + if (encrypt) {
1092 + cmd |= HACE_CMD_ENCRYPT;
1093 + }
1094 +
1095 + crypt_write_ctx(s, ctx, t);
1096 + crypt_make_sg(s, dram, CRYPT_OFF_SRC, src_sg, in, t->len);
1097 + crypt_make_sg(s, dram, CRYPT_OFF_DST, dst_sg, NULL, t->len);
1098 +
1099 + qtest_writel(s, base + HACE_CRYPTO_SRC, (uint32_t)src_sg);
1100 + qtest_writel(s, base + HACE_CRYPTO_DEST, (uint32_t)dst_sg);
1101 + qtest_writel(s, base + HACE_CRYPTO_CONTEXT, (uint32_t)ctx);
1102 + qtest_writel(s, base + HACE_CRYPTO_DATA_LEN, t->len);
1103 + qtest_writel(s, base + HACE_CRYPTO_CMD, cmd);
1104 +
1105 + g_assert_cmphex(qtest_readl(s, base + HACE_STS) & HACE_CRYPTO_ISR, ==,
1106 + HACE_CRYPTO_ISR);
1107 + qtest_writel(s, base + HACE_STS, HACE_CRYPTO_ISR);
1108 +
1109 + crypt_gather_sg(s, dram, CRYPT_OFF_DST, out, t->len);
1110 +}
1111 +
1112 +static void aspeed_test_crypto(const void *data)
1113 {
1114 const AspeedCryptoTest *c = data;
1115 const CryptTest *t = &crypt_tests[c->index];
@@ -924,7 +1121,11 @@ static void aspeed_test_crypto_direct(const void *data)
1121 g_assert_cmpuint(t->len, <=, sizeof(out));
1122
1123 /* Encrypt: ptext -> ctext */
927 - crypt_run_direct(s, c->base, c->dram, t, true, out);
1124 + if (c->sg) {
1125 + crypt_run_sg(s, c->base, c->dram, t, true, out);
1126 + } else {
1127 + crypt_run_direct(s, c->base, c->dram, t, true, out);
1128 + }
1129 g_assert_cmpmem(out, t->len, t->ctext, t->len);
1130
1131 if (t->iv_out) {
@@ -934,14 +1135,19 @@ static void aspeed_test_crypto_direct(const void *data)
1135 }
1136
1137 /* Decrypt: ctext -> ptext */
937 - crypt_run_direct(s, c->base, c->dram, t, false, out);
1138 + if (c->sg) {
1139 + crypt_run_sg(s, c->base, c->dram, t, false, out);
1140 + } else {
1141 + crypt_run_direct(s, c->base, c->dram, t, false, out);
1142 + }
1143 g_assert_cmpmem(out, t->len, t->ptext, t->len);
1144
1145 qtest_quit(s);
1146 }
1147
1148 void aspeed_add_crypto_tests(const char *prefix, const char *machine,
944 - uint32_t base, uint64_t dram, uint32_t modes)
1149 + uint32_t base, uint64_t dram, uint32_t modes,
1150 + bool sg)
1151 {
1152 int i;
1153
@@ -966,7 +1172,8 @@ void aspeed_add_crypto_tests(const char *prefix, const char *machine,
1172 t->base = base;
1173 t->dram = dram;
1174 t->index = i;
969 - qtest_add_data_func_full(path, t, aspeed_test_crypto_direct, g_free);
1175 + t->sg = sg;
1176 + qtest_add_data_func_full(path, t, aspeed_test_crypto, g_free);
1177 }
1178 }
1179
tests/qtest/aspeed-hace-utils.h
+5 -2
@@ -85,15 +85,18 @@ void aspeed_test_addresses(const char *machine, const uint32_t base,
85 enum {
86 CRYPT_MODE_ECB = 1 << 0,
87 CRYPT_MODE_CBC = 1 << 1,
88 + CRYPT_MODE_CTR = 1 << 2,
89 };
90
91 /*
92 * Register the crypto known-answer tests that @modes selects (a mask of
93 * CRYPT_MODE_*) for the given machine. Each test is named
93 - * "<prefix>/hace/crypto/<mode>".
94 + * "<prefix>/hace/crypto/<mode>". @sg selects scatter-gather mode (used by the
95 + * AST2600 and later) instead of the AST2500 direct access mode.
96 */
97 void aspeed_add_crypto_tests(const char *prefix, const char *machine,
96 - uint32_t base, uint64_t dram, uint32_t modes);
98 + uint32_t base, uint64_t dram, uint32_t modes,
99 + bool sg);
100
101 #endif /* TESTS_ASPEED_HACE_UTILS_H */
102
tests/qtest/aspeed_hace-test.c
+7 -1
@@ -224,6 +224,12 @@ int main(int argc, char **argv)
224 qtest_add_func("ast2600/hace/sha384_accum", test_sha384_accum_ast2600);
225 qtest_add_func("ast2600/hace/sha256_accum", test_sha256_accum_ast2600);
226
227 + /* The AST2600 crypto engine uses scatter-gather mode and adds CTR. */
228 + aspeed_add_crypto_tests("ast2600", "-machine ast2600-evb", 0x1e6d0000,
229 + 0x80000000,
230 + CRYPT_MODE_ECB | CRYPT_MODE_CBC | CRYPT_MODE_CTR,
231 + true);
232 +
233 qtest_add_func("ast2500/hace/addresses", test_addresses_ast2500);
234 qtest_add_func("ast2500/hace/sha512", test_sha512_ast2500);
235 qtest_add_func("ast2500/hace/sha256", test_sha256_ast2500);
@@ -233,7 +239,7 @@ int main(int argc, char **argv)
239 * The AST2500 crypto engine uses direct access mode and supports ECB/CBC.
240 */
241 aspeed_add_crypto_tests("ast2500", "-machine ast2500-evb", 0x1e6e3000,
236 - 0x80000000, CRYPT_MODE_ECB | CRYPT_MODE_CBC);
242 + 0x80000000, CRYPT_MODE_ECB | CRYPT_MODE_CBC, false);
243
244 qtest_add_func("ast2400/hace/addresses", test_addresses_ast2400);
245 qtest_add_func("ast2400/hace/sha512", test_sha512_ast2400);