RE: [PATCH v3 05/16] tests/qtest/aspeed-hace: Test the crypto command on the AST2600
Kane Chen <[email protected]>
| Newsgroups | org.nongnu.qemu-arm,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <SI6PR06MB76318CB68A5D38535AEA4C73F7DD2@SI6PR06MB7631.apcprd06.prod.outlook.com> |
> -----Original Message----- > From: Jamin Lin <[email protected]> > Sent: Tuesday, August 11, 2026 11:11 AM > To: Daniel P. Berrangé <[email protected]>; Cédric Le Goater > <[email protected]>; Peter Maydell <[email protected]>; Steven Lee > <[email protected]>; Troy Lee <[email protected]>; Kane Chen > <[email protected]>; Andrew Jeffery > <[email protected]>; Joel Stanley <[email protected]>; Eric Blake > <[email protected]>; Markus Armbruster <[email protected]>; Fabiano > Rosas <[email protected]>; Laurent Vivier <[email protected]>; Paolo Bonzini > <[email protected]>; open list:All patches CC here > <[email protected]>; open list:ASPEED BMCs > <[email protected]> > Cc: Jamin Lin <[email protected]>; Troy Lee > <[email protected]> > Subject: [PATCH v3 05/16] 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 <[email protected]> > --- > tests/qtest/aspeed-hace-utils.h | 7 +- > tests/qtest/aspeed-hace-utils.c | 217 +++++++++++++++++++++++++++++++- > tests/qtest/aspeed_hace-test.c | 8 +- > 3 files changed, 224 insertions(+), 8 deletions(-) > > diff --git a/tests/qtest/aspeed-hace-utils.h b/tests/qtest/aspeed-hace-utils.h > index 13feaa61e4..82b0b3f93d 100644 > --- a/tests/qtest/aspeed-hace-utils.h > +++ b/tests/qtest/aspeed-hace-utils.h > @@ -85,15 +85,18 @@ void aspeed_test_addresses(const char *machine, > const uint32_t base, enum { > CRYPT_MODE_ECB = 1 << 0, > CRYPT_MODE_CBC = 1 << 1, > + CRYPT_MODE_CTR = 1 << 2, > }; > > /* > * Register the crypto known-answer tests that @modes selects (a mask of > * CRYPT_MODE_*) for the given machine. Each test is named > - * "<prefix>/hace/crypto/<mode>". > + * "<prefix>/hace/crypto/<mode>". @sg selects scatter-gather mode (used > + by the > + * AST2600 and later) instead of the AST2500 direct access mode. > */ > void aspeed_add_crypto_tests(const char *prefix, const char *machine, > - uint32_t base, uint64_t dram, uint32_t > modes); > + uint32_t base, uint64_t dram, uint32_t > modes, > + bool sg); > > #endif /* TESTS_ASPEED_HACE_UTILS_H */ > > diff --git a/tests/qtest/aspeed-hace-utils.c b/tests/qtest/aspeed-hace-utils.c > index 0355dd47af..f582c88ef5 100644 > --- a/tests/qtest/aspeed-hace-utils.c > +++ b/tests/qtest/aspeed-hace-utils.c > @@ -665,6 +665,7 @@ void aspeed_test_addresses(const char *machine, > const uint32_t base, > #define HACE_CMD_OP_MODE_MASK (0x7 << 4) > #define HACE_CMD_ECB (0x0 << 4) > #define HACE_CMD_CBC (0x1 << 4) > +#define HACE_CMD_CTR (0x4 << 4) > #define HACE_CMD_AES128 (0x0 << 2) > > /* Context buffer layout: IV (DES at +8), key at +0x10 */ @@ -750,6 +751,49 > @@ static const uint8_t tdes_cbc_ptext[8] = { static const uint8_t > tdes_cbc_ctext[8] = { > 0x0e, 0x2d, 0xb6, 0x97, 0x3c, 0x56, 0x33, 0xf4 }; > > +/* aes_ctr_tv_template[0] (NIST SP800-38A F.5.1), first block */ static > +const uint8_t aes128_ctr_key[16] = { > + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, > + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }; static const > +uint8_t aes128_ctr_iv[16] = { > + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, > + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; static const > +uint8_t aes128_ctr_ptext[16] = { > + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, > + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a }; static const > +uint8_t aes128_ctr_ctext[16] = { > + 0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, > + 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce }; static const > +uint8_t aes128_ctr_ivout[16] = { > + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, > + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xff, 0x00 }; > + > +/* des_ctr_tv_template[0] (Crypto++), first block */ static const > +uint8_t des_ctr_key[8] = { > + 0xc9, 0x83, 0xa6, 0xc9, 0xec, 0x0f, 0x32, 0x55 }; static const > +uint8_t des_ctr_iv[8] = { > + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd }; static const > +uint8_t des_ctr_ptext[8] = { > + 0x50, 0xb9, 0x22, 0xae, 0x17, 0x80, 0x0c, 0x75 }; static const > +uint8_t des_ctr_ctext[8] = { > + 0x2f, 0x96, 0x06, 0x0f, 0x50, 0xc9, 0x68, 0x03 }; static const > +uint8_t des_ctr_ivout[8] = { > + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe }; > + > +/* des3_ede_ctr_tv_template[0] (Crypto++), first block */ static const > +uint8_t tdes_ctr_key[24] = { > + 0x9c, 0xd6, 0xf3, 0x9c, 0xb9, 0x5a, 0x67, 0x00, > + 0x5a, 0x67, 0x00, 0x2d, 0xce, 0xeb, 0x2d, 0xce, > + 0xeb, 0xb4, 0x51, 0x72, 0xb4, 0x51, 0x72, 0x1f }; static const > +uint8_t tdes_ctr_iv[8] = { > + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; static const > +uint8_t tdes_ctr_ptext[8] = { > + 0x05, 0xec, 0x77, 0xfb, 0x42, 0xd5, 0x59, 0x20 }; static const > +uint8_t tdes_ctr_ctext[8] = { > + 0x07, 0xc2, 0x08, 0x20, 0x72, 0x1f, 0x49, 0xef }; static const > +uint8_t tdes_ctr_ivout[8] = { > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; > + > typedef struct CryptTest { > QCryptoCipherMode mode; > QCryptoCipherAlgo alg; > @@ -841,12 +885,65 @@ static const CryptTest crypt_tests[] = { > .ctext = tdes_cbc_ctext, > .len = sizeof(tdes_cbc_ptext), > }, > + { > + .name = "aes128-ctr", > + .cmd = HACE_CMD_AES128 | HACE_CMD_CTR, > + .alg = QCRYPTO_CIPHER_ALGO_AES_128, > + .mode = QCRYPTO_CIPHER_MODE_CTR, > + .key = aes128_ctr_key, > + .keylen = sizeof(aes128_ctr_key), > + .iv = aes128_ctr_iv, > + .ivlen = sizeof(aes128_ctr_iv), > + .ptext = aes128_ctr_ptext, > + .ctext = aes128_ctr_ctext, > + .iv_out = aes128_ctr_ivout, > + .len = sizeof(aes128_ctr_ptext), > + }, > + { > + .name = "des-ctr", > + .cmd = HACE_CMD_DES_SELECT | HACE_CMD_CTR, > + .alg = QCRYPTO_CIPHER_ALGO_DES, > + .mode = QCRYPTO_CIPHER_MODE_CTR, > + .key = des_ctr_key, > + .keylen = sizeof(des_ctr_key), > + .iv = des_ctr_iv, > + .ivlen = sizeof(des_ctr_iv), > + .ptext = des_ctr_ptext, > + .ctext = des_ctr_ctext, > + .iv_out = des_ctr_ivout, > + .len = sizeof(des_ctr_ptext), > + }, > + { > + .name = "des3_ede-ctr", > + .cmd = HACE_CMD_DES_SELECT | HACE_CMD_TRIPLE_DES | > HACE_CMD_CTR, > + .alg = QCRYPTO_CIPHER_ALGO_3DES, > + .mode = QCRYPTO_CIPHER_MODE_CTR, > + .key = tdes_ctr_key, > + .keylen = sizeof(tdes_ctr_key), > + .iv = tdes_ctr_iv, > + .ivlen = sizeof(tdes_ctr_iv), > + .ptext = tdes_ctr_ptext, > + .ctext = tdes_ctr_ctext, > + .iv_out = tdes_ctr_ivout, > + .len = sizeof(tdes_ctr_ptext), > + }, > }; > > /* DRAM offsets for the crypto test source, destination and context buffers. */ > #define CRYPT_OFF_SRC 0x10000 > #define CRYPT_OFF_DST 0x20000 > #define CRYPT_OFF_CTX 0x30000 > +/* Scatter-gather list offsets (each list has CRYPT_SG_FRAGS entries). > +*/ #define CRYPT_OFF_SRC_SG 0x40000 #define CRYPT_OFF_DST_SG > 0x50000 > +/* > + * The scatter-gather tests split each buffer into CRYPT_SG_FRAGS > +fragments, > + * each placed CRYPT_SG_FRAG_STRIDE apart so the fragments never abut. > +The gaps > + * make the test fail if the engine ignores the list and reads one > +contiguous > + * block. > + */ > +#define CRYPT_SG_FRAGS 3 > +#define CRYPT_SG_FRAG_STRIDE 0x1000 > > /* Describes one registered crypto test (qtest_add_data_func() data pointer). > */ typedef struct AspeedCryptoTest { @@ -854,6 +951,7 @@ typedef struct > AspeedCryptoTest { > uint64_t dram; > uint32_t base; > int index; > + bool sg; > } AspeedCryptoTest; > > /* 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) > return CRYPT_MODE_ECB; > case HACE_CMD_CBC: > return CRYPT_MODE_CBC; > + case HACE_CMD_CTR: > + return CRYPT_MODE_CTR; > default: > return 0; > } > @@ -912,7 +1012,104 @@ static void crypt_run_direct(QTestState *s, uint32_t > base, uint64_t dram, > qtest_memread(s, dst, out, t->len); } > > -static void aspeed_test_crypto_direct(const void *data) > +/* > + * Byte range [*frag_off, *frag_off + *frag_len) of fragment @index > +when an > + * @len-byte buffer is split into CRYPT_SG_FRAGS pieces; the last piece > +takes > + * the remainder of an uneven split. > + */ > +static void crypt_frag_range(uint32_t len, int index, > + uint32_t *frag_off, uint32_t *frag_len) { > + uint32_t base = len / CRYPT_SG_FRAGS; > + > + *frag_off = base * index; > + *frag_len = (index == CRYPT_SG_FRAGS - 1) ? len - *frag_off : base; > +} > + > +/* > + * Scatter [in, len) across CRYPT_SG_FRAGS buffers based at @base_off > +and spaced > + * CRYPT_SG_FRAG_STRIDE apart, then build the SG list describing them at > @list. > + * When @in is NULL only the list is built (used for the destination, > +which the > + * engine fills in). > + */ > +static void crypt_make_sg(QTestState *s, uint64_t dram, uint32_t base_off, > + uint64_t list, const uint8_t *in, uint32_t > +len) { > + struct AspeedSgList sg[CRYPT_SG_FRAGS]; > + uint32_t frag_off; > + uint32_t frag_len; > + uint64_t buf; > + int i; > + > + for (i = 0; i < CRYPT_SG_FRAGS; i++) { > + crypt_frag_range(len, i, &frag_off, &frag_len); > + buf = dram + base_off + i * CRYPT_SG_FRAG_STRIDE; > + > + if (in) { > + qtest_memwrite(s, buf, in + frag_off, frag_len); > + } > + sg[i].len = cpu_to_le32(frag_len | (i == CRYPT_SG_FRAGS - 1 ? > + SG_LIST_LEN_LAST : > 0)); > + sg[i].addr = cpu_to_le32((uint32_t)buf); > + } > + > + qtest_memwrite(s, list, sg, sizeof(sg)); } > + > +/* Gather a scatter-gathered result back from the CRYPT_SG_FRAGS > +buffers. */ static void crypt_gather_sg(QTestState *s, uint64_t dram, uint32_t > base_off, > + uint8_t *out, uint32_t len) { > + uint32_t frag_off; > + uint32_t frag_len; > + int i; > + > + for (i = 0; i < CRYPT_SG_FRAGS; i++) { > + crypt_frag_range(len, i, &frag_off, &frag_len); > + qtest_memread(s, dram + base_off + i * CRYPT_SG_FRAG_STRIDE, > + out + frag_off, frag_len); > + } > +} > + > +/* > + * Run one block-cipher (ECB/CBC/CTR) operation in scatter-gather mode > +and read > + * back the result. The source and destination are each split across > + * CRYPT_SG_FRAGS non-adjacent DRAM buffers described by an SG list; > +the gaps > + * ensure the test fails if the engine ignores the list and reads one > + * contiguous block. > + */ > +static void crypt_run_sg(QTestState *s, uint32_t base, uint64_t dram, > + const CryptTest *t, bool encrypt, uint8_t > +*out) { > + const uint8_t *in = encrypt ? t->ptext : t->ctext; > + uint64_t src_sg = dram + CRYPT_OFF_SRC_SG; > + uint64_t dst_sg = dram + CRYPT_OFF_DST_SG; > + uint64_t ctx = dram + CRYPT_OFF_CTX; > + uint32_t cmd = t->cmd | HACE_CMD_ISR_EN | > HACE_CMD_SRC_SG_CTRL | > + HACE_CMD_DST_SG_CTRL; > + > + if (encrypt) { > + cmd |= HACE_CMD_ENCRYPT; > + } > + > + crypt_write_ctx(s, ctx, t); > + crypt_make_sg(s, dram, CRYPT_OFF_SRC, src_sg, in, t->len); > + crypt_make_sg(s, dram, CRYPT_OFF_DST, dst_sg, NULL, t->len); > + > + qtest_writel(s, base + HACE_CRYPTO_SRC, (uint32_t)src_sg); > + qtest_writel(s, base + HACE_CRYPTO_DEST, (uint32_t)dst_sg); > + qtest_writel(s, base + HACE_CRYPTO_CONTEXT, (uint32_t)ctx); > + qtest_writel(s, base + HACE_CRYPTO_DATA_LEN, t->len); > + qtest_writel(s, base + HACE_CRYPTO_CMD, cmd); > + > + g_assert_cmphex(qtest_readl(s, base + HACE_STS) & HACE_CRYPTO_ISR, > ==, > + HACE_CRYPTO_ISR); > + qtest_writel(s, base + HACE_STS, HACE_CRYPTO_ISR); > + > + crypt_gather_sg(s, dram, CRYPT_OFF_DST, out, t->len); } > + > +static void aspeed_test_crypto(const void *data) > { > const AspeedCryptoTest *c = data; > const CryptTest *t = &crypt_tests[c->index]; @@ -924,7 +1121,11 @@ > static void aspeed_test_crypto_direct(const void *data) > g_assert_cmpuint(t->len, <=, sizeof(out)); > > /* Encrypt: ptext -> ctext */ > - crypt_run_direct(s, c->base, c->dram, t, true, out); > + if (c->sg) { > + crypt_run_sg(s, c->base, c->dram, t, true, out); > + } else { > + crypt_run_direct(s, c->base, c->dram, t, true, out); > + } > g_assert_cmpmem(out, t->len, t->ctext, t->len); > > if (t->iv_out) { > @@ -934,14 +1135,19 @@ static void aspeed_test_crypto_direct(const void > *data) > } > > /* Decrypt: ctext -> ptext */ > - crypt_run_direct(s, c->base, c->dram, t, false, out); > + if (c->sg) { > + crypt_run_sg(s, c->base, c->dram, t, false, out); > + } else { > + crypt_run_direct(s, c->base, c->dram, t, false, out); > + } > g_assert_cmpmem(out, t->len, t->ptext, t->len); > > qtest_quit(s); > } > > void aspeed_add_crypto_tests(const char *prefix, const char *machine, > - uint32_t base, uint64_t dram, uint32_t > modes) > + uint32_t base, uint64_t dram, uint32_t > modes, > + bool sg) > { > int i; > > @@ -966,7 +1172,8 @@ void aspeed_add_crypto_tests(const char *prefix, > const char *machine, > t->base = base; > t->dram = dram; > t->index = i; > - qtest_add_data_func_full(path, t, aspeed_test_crypto_direct, > g_free); > + t->sg = sg; > + qtest_add_data_func_full(path, t, aspeed_test_crypto, g_free); > } > } > > diff --git a/tests/qtest/aspeed_hace-test.c b/tests/qtest/aspeed_hace-test.c > index 4cb4c475e9..61a3e3feb5 100644 > --- a/tests/qtest/aspeed_hace-test.c > +++ b/tests/qtest/aspeed_hace-test.c > @@ -224,6 +224,12 @@ int main(int argc, char **argv) > qtest_add_func("ast2600/hace/sha384_accum", > test_sha384_accum_ast2600); > qtest_add_func("ast2600/hace/sha256_accum", > test_sha256_accum_ast2600); > > + /* The AST2600 crypto engine uses scatter-gather mode and adds CTR. > */ > + aspeed_add_crypto_tests("ast2600", "-machine ast2600-evb", > 0x1e6d0000, > + 0x80000000, > + CRYPT_MODE_ECB | CRYPT_MODE_CBC | > CRYPT_MODE_CTR, > + true); > + > qtest_add_func("ast2500/hace/addresses", test_addresses_ast2500); > qtest_add_func("ast2500/hace/sha512", test_sha512_ast2500); > qtest_add_func("ast2500/hace/sha256", test_sha256_ast2500); @@ > -233,7 +239,7 @@ int main(int argc, char **argv) > * The AST2500 crypto engine uses direct access mode and supports > ECB/CBC. > */ > aspeed_add_crypto_tests("ast2500", "-machine ast2500-evb", > 0x1e6e3000, > - 0x80000000, CRYPT_MODE_ECB | > CRYPT_MODE_CBC); > + 0x80000000, CRYPT_MODE_ECB | > + CRYPT_MODE_CBC, false); > > qtest_add_func("ast2400/hace/addresses", test_addresses_ast2400); > qtest_add_func("ast2400/hace/sha512", test_sha512_ast2400); > -- > 2.43.0 Reviewed-by: Kane Chen <[email protected]>