> -----Original Message-----
> From: Jamin Lin <[email protected]>
> Sent: Wednesday, July 15, 2026 11:34 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 v2 16/17] 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 <[email protected]>
> ---
>  tests/qtest/aspeed-hace-utils.h |   1 +
>  tests/qtest/aspeed-hace-utils.c | 163 +++++++++++++++++++++++++++++++-
>  tests/qtest/ast2700-hace-test.c |   9 ++
>  3 files changed, 172 insertions(+), 1 deletion(-)
> 
> diff --git a/tests/qtest/aspeed-hace-utils.h b/tests/qtest/aspeed-hace-utils.h
> index 82b0b3f93d..a5601a3d65 100644
> --- a/tests/qtest/aspeed-hace-utils.h
> +++ b/tests/qtest/aspeed-hace-utils.h
> @@ -86,6 +86,7 @@ enum {
>      CRYPT_MODE_ECB = 1 << 0,
>      CRYPT_MODE_CBC = 1 << 1,
>      CRYPT_MODE_CTR = 1 << 2,
> +    CRYPT_MODE_GCM = 1 << 3,
>  };
> 
>  /*
> diff --git a/tests/qtest/aspeed-hace-utils.c b/tests/qtest/aspeed-hace-utils.c
> index f582c88ef5..260eec043c 100644
> --- a/tests/qtest/aspeed-hace-utils.c
> +++ b/tests/qtest/aspeed-hace-utils.c
> @@ -654,6 +654,8 @@ void aspeed_test_addresses(const char *machine,
> const uint32_t base,
>  #define HACE_CRYPTO_CONTEXT      0x08
>  #define HACE_CRYPTO_DATA_LEN     0x0c
>  #define HACE_CRYPTO_CMD          0x10
> +#define HACE_CRYPTO_GCM_ADD_LEN  0x14
> +#define HACE_CRYPTO_GCM_TAG      0x18
> 
>  /* Crypto command bits */
>  #define HACE_CMD_ENCRYPT         BIT(7)
> @@ -666,7 +668,9 @@ void aspeed_test_addresses(const char *machine,
> const uint32_t base,
>  #define HACE_CMD_ECB             (0x0 << 4)
>  #define HACE_CMD_CBC             (0x1 << 4)
>  #define HACE_CMD_CTR             (0x4 << 4)
> +#define HACE_CMD_GCM             (0x5 << 4)
>  #define HACE_CMD_AES128          (0x0 << 2)
> +#define HACE_CMD_AES256          (0x2 << 2)
> 
>  /* Context buffer layout: IV (DES at +8), key at +0x10 */
>  #define HACE_CTX_KEY_OFFSET      0x10
> @@ -794,6 +798,59 @@ static const uint8_t tdes_ctr_ctext[8] = {  static const
> uint8_t tdes_ctr_ivout[8] = {
>      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
> 
> +/*
> + * aes_gcm_tv_template[2] (AES-128) and [9] (AES-256), from the McGrew
> +& Viega
> + * GCM spec (also NIST SP 800-38D), no AAD. Both cases share this
> plaintext/IV.
> + */
> +static const uint8_t aes_gcm_ptext[64] = {
> +    0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
> +    0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
> +    0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
> +    0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
> +    0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
> +    0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
> +    0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
> +    0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 }; static const
> +uint8_t aes_gcm_iv[12] = {
> +    0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
> +    0xde, 0xca, 0xf8, 0x88 };
> +
> +/* aes_gcm_tv_template[2] (AES-128) */
> +static const uint8_t aes128_gcm_key[16] = {
> +    0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
> +    0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 }; static const
> +uint8_t aes128_gcm_ctext[64] = {
> +    0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24,
> +    0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c,
> +    0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0,
> +    0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e,
> +    0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c,
> +    0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05,
> +    0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
> +    0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85 }; static const
> +uint8_t aes128_gcm_tag[16] = {
> +    0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6,
> +    0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4 };
> +
> +/* aes_gcm_tv_template[9] (AES-256) */
> +static const uint8_t aes256_gcm_key[32] = {
> +    0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
> +    0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
> +    0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
> +    0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 }; static const
> +uint8_t aes256_gcm_ctext[64] = {
> +    0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07,
> +    0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d,
> +    0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9,
> +    0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa,
> +    0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d,
> +    0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38,
> +    0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
> +    0xbc, 0xc9, 0xf6, 0x62, 0x89, 0x80, 0x15, 0xad }; static const
> +uint8_t aes256_gcm_tag[16] = {
> +    0xb0, 0x94, 0xda, 0xc5, 0xd9, 0x34, 0x71, 0xbd,
> +    0xec, 0x1a, 0x50, 0x22, 0x70, 0xe3, 0xcc, 0x6c };
> +
>  typedef struct CryptTest {
>      QCryptoCipherMode mode;
>      QCryptoCipherAlgo alg;
> @@ -801,10 +858,13 @@ typedef struct CryptTest {
>      const uint8_t *iv_out;
>      const uint8_t *ptext;
>      const uint8_t *ctext;
> +    /* expected GCM authentication tag, or NULL for non-AEAD modes */
> +    const uint8_t *tag;
>      const uint8_t *key;
>      const uint8_t *iv;
>      const char *name;
>      size_t keylen;
> +    size_t taglen;
>      /* algorithm | mode | key size selection */
>      uint32_t cmd;
>      size_t ivlen;
> @@ -927,6 +987,36 @@ static const CryptTest crypt_tests[] = {
>          .iv_out = tdes_ctr_ivout,
>          .len = sizeof(tdes_ctr_ptext),
>      },
> +    {
> +        .name = "aes128-gcm",
> +        .cmd = HACE_CMD_AES128 | HACE_CMD_GCM,
> +        .alg = QCRYPTO_CIPHER_ALGO_AES_128,
> +        .mode = QCRYPTO_CIPHER_MODE_GCM,
> +        .key = aes128_gcm_key,
> +        .keylen = sizeof(aes128_gcm_key),
> +        .iv = aes_gcm_iv,
> +        .ivlen = sizeof(aes_gcm_iv),
> +        .ptext = aes_gcm_ptext,
> +        .ctext = aes128_gcm_ctext,
> +        .tag = aes128_gcm_tag,
> +        .taglen = sizeof(aes128_gcm_tag),
> +        .len = sizeof(aes_gcm_ptext),
> +    },
> +    {
> +        .name = "aes256-gcm",
> +        .cmd = HACE_CMD_AES256 | HACE_CMD_GCM,
> +        .alg = QCRYPTO_CIPHER_ALGO_AES_256,
> +        .mode = QCRYPTO_CIPHER_MODE_GCM,
> +        .key = aes256_gcm_key,
> +        .keylen = sizeof(aes256_gcm_key),
> +        .iv = aes_gcm_iv,
> +        .ivlen = sizeof(aes_gcm_iv),
> +        .ptext = aes_gcm_ptext,
> +        .ctext = aes256_gcm_ctext,
> +        .tag = aes256_gcm_tag,
> +        .taglen = sizeof(aes256_gcm_tag),
> +        .len = sizeof(aes_gcm_ptext),
> +    },
>  };
> 
>  /* DRAM offsets for the crypto test source, destination and context buffers. 
> */
> @@ -944,6 +1034,8 @@ static const CryptTest crypt_tests[] = {
>   */
>  #define CRYPT_SG_FRAGS         3
>  #define CRYPT_SG_FRAG_STRIDE   0x1000
> +/* DRAM offset for the AES-GCM authentication tag write buffer. */
> +#define CRYPT_OFF_TAG          0x60000
> 
>  /* Describes one registered crypto test (qtest_add_data_func() data pointer).
> */  typedef struct AspeedCryptoTest { @@ -964,6 +1056,8 @@ static uint32_t
> crypt_mode_flag(uint32_t cmd)
>          return CRYPT_MODE_CBC;
>      case HACE_CMD_CTR:
>          return CRYPT_MODE_CTR;
> +    case HACE_CMD_GCM:
> +        return CRYPT_MODE_GCM;
>      default:
>          return 0;
>      }
> @@ -1109,6 +1203,47 @@ static void crypt_run_sg(QTestState *s, uint32_t
> base, uint64_t dram,
>      crypt_gather_sg(s, dram, CRYPT_OFF_DST, out, t->len);  }
> 
> +/*
> + * Run one AES-GCM operation in scatter-gather mode: like
> +crypt_run_sg() but
> + * also program the tag write buffer (HACE18) with no associated data,
> +and read
> + * the authentication tag back into @out_tag.
> + */
> +static void crypt_run_gcm(QTestState *s, uint32_t base, uint64_t dram,
> +                          const CryptTest *t, bool encrypt, uint8_t *out,
> +                          uint8_t *out_tag) {
> +    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_GCM_ADD_LEN, 0);
> +    qtest_writel(s, base + HACE_CRYPTO_GCM_TAG,
> +                 (uint32_t)(dram + CRYPT_OFF_TAG));
> +    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);
> +    qtest_memread(s, dram + CRYPT_OFF_TAG, out_tag, t->taglen); }
> +
>  static void aspeed_test_crypto(const void *data)  {
>      const AspeedCryptoTest *c = data;
> @@ -1145,6 +1280,29 @@ static void aspeed_test_crypto(const void *data)
>      qtest_quit(s);
>  }
> 
> +static void aspeed_test_crypto_gcm(const void *data) {
> +    const AspeedCryptoTest *c = data;
> +    const CryptTest *t = &crypt_tests[c->index];
> +    QTestState *s = qtest_init(c->machine);
> +    uint8_t out[64];
> +    uint8_t tag[16];
> +
> +    g_assert_cmpuint(t->len, <=, sizeof(out));
> +
> +    /* Encrypt: ptext -> ctext, then check the authentication tag. */
> +    crypt_run_gcm(s, c->base, c->dram, t, true, out, tag);
> +    g_assert_cmpmem(out, t->len, t->ctext, t->len);
> +    g_assert_cmpmem(tag, t->taglen, t->tag, t->taglen);
> +
> +    /* Decrypt: ctext -> ptext, the recomputed tag must match. */
> +    crypt_run_gcm(s, c->base, c->dram, t, false, out, tag);
> +    g_assert_cmpmem(out, t->len, t->ptext, t->len);
> +    g_assert_cmpmem(tag, t->taglen, t->tag, t->taglen);
> +
> +    qtest_quit(s);
> +}
> +
>  void aspeed_add_crypto_tests(const char *prefix, const char *machine,
>                               uint32_t base, uint64_t dram, uint32_t
> modes,
>                               bool sg)
> @@ -1152,6 +1310,7 @@ void aspeed_add_crypto_tests(const char *prefix,
> const char *machine,
>      int i;
> 
>      for (i = 0; i < ARRAY_SIZE(crypt_tests); i++) {
> +        bool is_gcm = crypt_tests[i].mode ==
> QCRYPTO_CIPHER_MODE_GCM;
>          g_autofree char *path = NULL;
>          AspeedCryptoTest *t;
> 
> @@ -1173,7 +1332,9 @@ void aspeed_add_crypto_tests(const char *prefix,
> const char *machine,
>          t->dram = dram;
>          t->index = i;
>          t->sg = sg;
> -        qtest_add_data_func_full(path, t, aspeed_test_crypto, g_free);
> +        qtest_add_data_func_full(path, t,
> +                                 is_gcm ? aspeed_test_crypto_gcm :
> +                                 aspeed_test_crypto, g_free);
>      }
>  }
> 
> diff --git a/tests/qtest/ast2700-hace-test.c b/tests/qtest/ast2700-hace-test.c
> index 508a34dd6c..3f0217d635 100644
> --- a/tests/qtest/ast2700-hace-test.c
> +++ b/tests/qtest/ast2700-hace-test.c
> @@ -94,5 +94,14 @@ int main(int argc, char **argv)
>      qtest_add_func("ast2700/hace/sha384_accum",
> test_sha384_accum_ast2700);
>      qtest_add_func("ast2700/hace/sha256_accum",
> test_sha256_accum_ast2700);
> 
> +    /*
> +     * The AST2700 crypto engine uses scatter-gather with 64-bit DMA and
> adds
> +     * AES-GCM on top of the ECB/CBC/CTR modes shared with the
> AST2600.
> +     */
> +    aspeed_add_crypto_tests("ast2700", "-machine ast2700-evb",
> 0x12070000,
> +                            0x400000000,
> +                            CRYPT_MODE_ECB | CRYPT_MODE_CBC |
> CRYPT_MODE_CTR |
> +                            CRYPT_MODE_GCM, true);
> +
>      return g_test_run();
>  }
> --
> 2.43.0

Reviewed-by: Kane Chen <[email protected]>

Reply via email to