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);