From: Jamin Lin <jamin_lin@aspeedtech.com>
To: "Daniel P. Berrangé" <berrange@redhat.com>,
"Cédric Le Goater" <clg@kaod.org>,
"Peter Maydell" <peter.maydell@linaro.org>,
"Steven Lee" <steven_lee@aspeedtech.com>,
"Troy Lee" <leetroy@gmail.com>,
"Kane Chen" <kane_chen@aspeedtech.com>,
"Andrew Jeffery" <andrew@codeconstruct.com.au>,
"Joel Stanley" <joel@jms.id.au>, "Eric Blake" <eblake@redhat.com>,
"Markus Armbruster" <armbru@redhat.com>,
"Fabiano Rosas" <farosas@suse.de>,
"Laurent Vivier" <lvivier@redhat.com>,
"Paolo Bonzini" <pbonzini@redhat.com>,
"open list:All patches CC here" <qemu-devel@nongnu.org>,
"open list:ASPEED BMCs" <qemu-arm@nongnu.org>
Cc: Jamin Lin <jamin_lin@aspeedtech.com>, Troy Lee <troy_lee@aspeedtech.com>
Subject: [PATCH v1 05/15] tests/qtest/aspeed-hace: Test the crypto command on the AST2600
Date: Tue, 14 Jul 2026 07:29:08 +0000 [thread overview]
Message-ID: <20260714072900.3023742-6-jamin_lin@aspeedtech.com> (raw)
In-Reply-To: <20260714072900.3023742-1-jamin_lin@aspeedtech.com>
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>
---
tests/qtest/aspeed-hace-utils.h | 7 +-
tests/qtest/aspeed-hace-utils.c | 211 +++++++++++++++++++++++++++++++-
tests/qtest/aspeed_hace-test.c | 8 +-
3 files changed, 218 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 4deb88dbcc..0b91a4e61a 100644
--- a/tests/qtest/aspeed-hace-utils.c
+++ b/tests/qtest/aspeed-hace-utils.c
@@ -664,6 +664,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 */
@@ -749,6 +750,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 {
const uint8_t *ptext;
const uint8_t *ctext;
@@ -826,12 +870,59 @@ static const CryptTest crypt_tests[] = {
.ctext = tdes_cbc_ctext,
.len = sizeof(tdes_cbc_ptext),
},
+ {
+ .name = "aes128-ctr",
+ .cmd = HACE_CMD_AES128 | HACE_CMD_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,
+ .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,
+ .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 {
@@ -839,6 +930,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. */
@@ -849,6 +941,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;
}
@@ -897,7 +991,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];
@@ -909,7 +1100,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) {
@@ -919,14 +1114,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;
@@ -945,7 +1145,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
next prev parent reply other threads:[~2026-07-14 7:31 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-14 7:29 [PATCH v1 00/15] Support the ASPEED HACE crypto command Jamin Lin
2026-07-14 7:29 ` [PATCH v1 01/15] hw/misc/aspeed_hace: Support the crypto command in direct access mode Jamin Lin
2026-07-14 7:29 ` [PATCH v1 02/15] tests/qtest/aspeed-hace: Test the crypto command on the AST2500 Jamin Lin
2026-07-14 7:29 ` [PATCH v1 03/15] hw/misc/aspeed_hace: Support scatter-gather mode for the crypto command Jamin Lin
2026-07-14 7:29 ` [PATCH v1 04/15] hw/misc/aspeed_hace: Support the CTR " Jamin Lin
2026-07-14 7:29 ` Jamin Lin [this message]
2026-07-14 10:16 ` [PATCH v1 05/15] tests/qtest/aspeed-hace: Test the crypto command on the AST2600 Cédric Le Goater
2026-07-14 7:29 ` [PATCH v1 06/15] tests/qtest/aspeed-hace: Test the crypto command on the AST1030 Jamin Lin
2026-07-14 7:29 ` [PATCH v1 07/15] crypto/cipher: Add GCM to QCryptoCipherMode Jamin Lin
2026-07-14 8:37 ` Daniel P. Berrangé
2026-07-14 7:29 ` [PATCH v1 08/15] crypto/cipher: Add setaad/gettag for AEAD modes Jamin Lin
2026-07-14 8:37 ` Daniel P. Berrangé
2026-07-14 7:29 ` [PATCH v1 09/15] crypto/cipher-gcrypt: Implement AES-GCM Jamin Lin
2026-07-14 8:39 ` Daniel P. Berrangé
2026-07-14 8:57 ` Jamin Lin
2026-07-14 9:31 ` Daniel P. Berrangé
2026-07-14 7:29 ` [PATCH v1 10/15] tests/unit/test-crypto-cipher: Test AES-GCM mode Jamin Lin
2026-07-14 7:29 ` [PATCH v1 11/15] hw/misc/aspeed_hace: Support 64-bit DMA for the crypto command Jamin Lin
2026-07-14 7:29 ` [PATCH v1 12/15] hw/misc/aspeed_hace: Support the AES-GCM mode " Jamin Lin
2026-07-14 7:29 ` [PATCH v1 13/15] hw/misc/aspeed_hace: Enable the crypto command on the AST2700 Jamin Lin
2026-07-14 7:29 ` [PATCH v1 14/15] tests/qtest/aspeed-hace: Test " Jamin Lin
2026-07-14 7:29 ` [PATCH v1 15/15] tests/functional/aarch64/test_aspeed_ast2700: Drop the AST2700 crypto self-test workaround Jamin Lin
2026-07-14 8:47 ` [PATCH v1 00/15] Support the ASPEED HACE crypto command Daniel P. Berrangé
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260714072900.3023742-6-jamin_lin@aspeedtech.com \
--to=jamin_lin@aspeedtech.com \
--cc=andrew@codeconstruct.com.au \
--cc=armbru@redhat.com \
--cc=berrange@redhat.com \
--cc=clg@kaod.org \
--cc=eblake@redhat.com \
--cc=farosas@suse.de \
--cc=joel@jms.id.au \
--cc=kane_chen@aspeedtech.com \
--cc=leetroy@gmail.com \
--cc=lvivier@redhat.com \
--cc=pbonzini@redhat.com \
--cc=peter.maydell@linaro.org \
--cc=qemu-arm@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=steven_lee@aspeedtech.com \
--cc=troy_lee@aspeedtech.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.