[PATCH v2 4/4] tests/qtest/aspeed-acry-test: Add RSA ModExp tests

Jamin Lin <[email protected]>
Newsgroups org.nongnu.qemu-arm,org.nongnu.qemu-devel
Message-ID <[email protected]>
Add qtest cases exercising the AST2600 ACRY RSA ModExp engine end to
end. Each case lays out the exponent, modulus and message in the
scattered SRAM byte layout the engine expects, triggers the
engine, checks that both completion bits (RSA_ENG_DONE and
RSA_DMA_DONE) are asserted together in the status register, reads the
result back from the result SRAM, and checks the status bits clear
afterwards.

Comparing the result against a known-answer ciphertext
also validates the SRAM byte mapping end to end.

The cases cover raw (unpadded) public-exponent RSA, c = m^e mod n -
exactly what the "rsa" akcipher transform backed by the ACRY FW
performs, since PKCS1 padding is applied by a separate template
layered on top in Linux, not by the ACRY hardware. QEMU's akcipher
backend only implements raw RSA via libgcrypt, so the tests skip
rather than fail when the build lacks it.

The 2048-bit and 4096-bit vectors are rsa_tv_template[2] and [3] from the
Linux kernel crypto self-test suite (crypto/testmgr.h, v6.18).

Signed-off-by: Jamin Lin <[email protected]>
---
 tests/qtest/aspeed-acry-test.c | 395 +++++++++++++++++++++++++++++++++
 tests/qtest/meson.build        |   5 +-
 2 files changed, 399 insertions(+), 1 deletion(-)
 create mode 100644 tests/qtest/aspeed-acry-test.c

diff --git a/tests/qtest/aspeed-acry-test.c b/tests/qtest/aspeed-acry-test.c
new file mode 100644
index 0000000000..c80323cfe2
--- /dev/null
+++ b/tests/qtest/aspeed-acry-test.c
@@ -0,0 +1,395 @@
+/*
+ * QTest testcase for the ASPEED ACRY Engine
+ *
+ * Copyright (C) 2026 ASPEED Technology Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qemu/bitops.h"
+#include "crypto/akcipher.h"
+
+#define ACRY_TRIGGER                0x000
+#define  ACRY_TRIGGER_RSA_DMA_DATA  BIT(1)
+#define  ACRY_TRIGGER_RSA_START     BIT(0)
+#define ACRY_DMA_CMD                0x048
+#define  ACRY_DMA_CMD_DMEM_AHB      BIT(8)
+#define  ACRY_DMA_CMD_SRAM_MODE_RSA (0x3 << 4)
+#define ACRY_DMA_SRC                0x04C
+#define ACRY_DMA_LEN                0x050
+#define ACRY_RSA_KEY_LEN            0x058
+#define ACRY_INT_MASK               0x3F8
+#define  ACRY_INT_MASK_RSA_DMA_MASK BIT(2)
+#define  ACRY_INT_MASK_RSA_ENG_MASK BIT(1)
+#define ACRY_STATUS                 0x3FC
+#define  ACRY_STATUS_RSA_DMA_DONE   BIT(2)
+#define  ACRY_STATUS_RSA_ENG_DONE   BIT(1)
+#define  ACRY_STATUS_RSA_DONE       (ACRY_STATUS_RSA_ENG_DONE | \
+                                     ACRY_STATUS_RSA_DMA_DONE)
+
+#define ACRY_DATA_MAX_LEN 0x800
+#define ACRY_SRAM_SIZE    (3 * ACRY_DATA_MAX_LEN)
+#define ACRY_MAX_BITS     4096
+#define ACRY_MAX_BYTES    (ACRY_MAX_BITS / 8)
+
+/* Dwords into each 12-dword block where each operand's region starts. */
+#define ACRY_EXP_OFFSET   0
+#define ACRY_MOD_OFFSET   4
+#define ACRY_DATA_OFFSET  8
+
+/*
+ * Raw (unpadded) RSA known-answer vectors: c = m^e mod n with
+ * e = 0x10001 (65537) - exactly what the "rsa" akcipher transform backed by
+ * the ACRY FW computes. PKCS1 padding is a separate "pkcs1pad(rsa)" template
+ * layered on top in Linux, not done by the ACRY hardware.
+ *
+ * rsa2048_* and rsa4096_* are from the Linux kernel crypto/testmgr.h (v6.18),
+ * rsa_tv_template[2] and [3]. Grep that file's own comment to find them:
+ *
+ *   RSA test vectors. Borrowed from openSSL.
+ *
+ *   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/crypto/testmgr.h?h=v6.18
+ *
+ * There the modulus n is DER-encoded in the .key field (not a raw field), the
+ * ciphertext is .c, and every entry reuses the same 8-byte .m message.
+ */
+/* rsa_tv_template[].m, shared by every entry */
+static const uint8_t rsa_m[8] = {
+    0x54, 0x85, 0x9B, 0x34, 0x2C, 0x49, 0xEA, 0x2A,
+};
+/* public exponent e = 65537, DER-encoded in every .key */
+static const uint8_t rsa_e[3] = { 0x01, 0x00, 0x01 };
+
+/* rsa_tv_template[2].key, modulus n */
+static const uint8_t rsa2048_n[256] = {
+    0xDB, 0x10, 0x1A, 0xC2, 0xA3, 0xF1, 0xDC, 0xFF, 0x13, 0x6B, 0xED, 0x44,
+    0xDF, 0xF0, 0x02, 0x6D, 0x13, 0xC7, 0x88, 0xDA, 0x70, 0x6B, 0x54, 0xF1,
+    0xE8, 0x27, 0xDC, 0xC3, 0x0F, 0x99, 0x6A, 0xFA, 0xC6, 0x67, 0xFF, 0x1D,
+    0x1E, 0x3C, 0x1D, 0xC1, 0xB5, 0x5F, 0x6C, 0xC0, 0xB2, 0x07, 0x3A, 0x6D,
+    0x41, 0xE4, 0x25, 0x99, 0xAC, 0xFC, 0xD2, 0x0F, 0x02, 0xD3, 0xD1, 0x54,
+    0x06, 0x1A, 0x51, 0x77, 0xBD, 0xB6, 0xBF, 0xEA, 0xA7, 0x5C, 0x06, 0xA9,
+    0x5D, 0x69, 0x84, 0x45, 0xD7, 0xF5, 0x05, 0xBA, 0x47, 0xF0, 0x1B, 0xD7,
+    0x2B, 0x24, 0xEC, 0xCB, 0x9B, 0x1B, 0x10, 0x8D, 0x81, 0xA0, 0xBE, 0xB1,
+    0x8C, 0x33, 0xE4, 0x36, 0xB8, 0x43, 0xEB, 0x19, 0x2A, 0x81, 0x8D, 0xDE,
+    0x81, 0x0A, 0x99, 0x48, 0xB6, 0xF6, 0xBC, 0xCD, 0x49, 0x34, 0x3A, 0x8F,
+    0x26, 0x94, 0xE3, 0x28, 0x82, 0x1A, 0x7C, 0x8F, 0x59, 0x9F, 0x45, 0xE8,
+    0x5D, 0x1A, 0x45, 0x76, 0x04, 0x56, 0x05, 0xA1, 0xD0, 0x1B, 0x8C, 0x77,
+    0x6D, 0xAF, 0x53, 0xFA, 0x71, 0xE2, 0x67, 0xE0, 0x9A, 0xFE, 0x03, 0xA9,
+    0x85, 0xD2, 0xC9, 0xAA, 0xBA, 0x2A, 0xBC, 0xF4, 0xA0, 0x08, 0xF5, 0x13,
+    0x98, 0x13, 0x5D, 0xF0, 0xD9, 0x33, 0x34, 0x2A, 0x61, 0xC3, 0x89, 0x55,
+    0xF0, 0xAE, 0x1A, 0x9C, 0x22, 0xEE, 0x19, 0x05, 0x8D, 0x32, 0xFE, 0xEC,
+    0x9C, 0x84, 0xBA, 0xB7, 0xF9, 0x6C, 0x3A, 0x4F, 0x07, 0xFC, 0x45, 0xEB,
+    0x12, 0xE5, 0x7B, 0xFD, 0x55, 0xE6, 0x29, 0x69, 0xD1, 0xC2, 0xE8, 0xB9,
+    0x78, 0x59, 0xF6, 0x79, 0x10, 0xC6, 0x4E, 0xEB, 0x6A, 0x5E, 0xB9, 0x9A,
+    0xC7, 0xC4, 0x5B, 0x63, 0xDA, 0xA3, 0x3F, 0x5E, 0x92, 0x7A, 0x81, 0x5E,
+    0xD6, 0xB0, 0xE2, 0x62, 0x8F, 0x74, 0x26, 0xC2, 0x0C, 0xD3, 0x9A, 0x17,
+    0x47, 0xE6, 0x8E, 0xAB,
+};
+/* rsa_tv_template[2].c */
+static const uint8_t rsa2048_c[256] = {
+    0xB2, 0x97, 0x76, 0xB4, 0xAE, 0x3E, 0x38, 0x3C, 0x7E, 0x64, 0x1F, 0xCC,
+    0xA2, 0x7F, 0xF6, 0xBE, 0xCF, 0x49, 0xBC, 0x48, 0xD3, 0x6C, 0x8F, 0x0A,
+    0x0E, 0xC1, 0x73, 0xBD, 0x7B, 0x55, 0x79, 0x36, 0x0E, 0xA1, 0x87, 0x88,
+    0xB9, 0x2C, 0x90, 0xA6, 0x53, 0x5E, 0xE9, 0xEF, 0xC4, 0xE2, 0x4D, 0xDD,
+    0xF7, 0xA6, 0x69, 0x82, 0x3F, 0x56, 0xA4, 0x7B, 0xFB, 0x62, 0xE0, 0xAE,
+    0xB8, 0xD3, 0x04, 0xB3, 0xAC, 0x5A, 0x15, 0x2A, 0xE3, 0x19, 0x9B, 0x03,
+    0x9A, 0x0B, 0x41, 0xDA, 0x64, 0xEC, 0x0A, 0x69, 0xFC, 0xF2, 0x10, 0x92,
+    0xF3, 0xC1, 0xBF, 0x84, 0x7F, 0xFD, 0x2C, 0xAE, 0xC8, 0xB5, 0xF6, 0x41,
+    0x70, 0xC5, 0x47, 0x03, 0x8A, 0xF8, 0xFF, 0x6F, 0x3F, 0xD2, 0x6F, 0x09,
+    0xB4, 0x22, 0xF3, 0x30, 0xBE, 0xA9, 0x85, 0xCB, 0x9C, 0x8D, 0xF9, 0x8F,
+    0xEB, 0x32, 0x91, 0xA2, 0x25, 0x84, 0x8F, 0xF5, 0xDC, 0xC7, 0x06, 0x9C,
+    0x2D, 0xE5, 0x11, 0x2C, 0x09, 0x09, 0x87, 0x09, 0xA9, 0xF6, 0x33, 0x73,
+    0x90, 0xF1, 0x60, 0xF2, 0x65, 0xDD, 0x30, 0xA5, 0x66, 0xCE, 0x62, 0x7B,
+    0xD0, 0xF8, 0x2D, 0x3D, 0x19, 0x82, 0x77, 0xE3, 0x0A, 0x5F, 0x75, 0x2F,
+    0x8E, 0xB1, 0xE5, 0xE8, 0x91, 0x35, 0x1B, 0x3B, 0x33, 0xB7, 0x66, 0x92,
+    0xD1, 0xF2, 0x8E, 0x6F, 0xE5, 0x75, 0x0C, 0xAD, 0x36, 0xFB, 0x4E, 0xD0,
+    0x66, 0x61, 0xBD, 0x49, 0xFE, 0xF4, 0x1A, 0xA2, 0x2B, 0x49, 0xFE, 0x03,
+    0x4C, 0x74, 0x47, 0x8D, 0x9A, 0x66, 0xB2, 0x49, 0x46, 0x4D, 0x77, 0xEA,
+    0x33, 0x4D, 0x6B, 0x3C, 0xB4, 0x49, 0x4A, 0xC6, 0x7D, 0x3D, 0xB5, 0xB9,
+    0x56, 0x41, 0x15, 0x67, 0x0F, 0x94, 0x3C, 0x93, 0x65, 0x27, 0xE0, 0x21,
+    0x5D, 0x59, 0xC3, 0x62, 0xD5, 0xA6, 0xDA, 0x38, 0x26, 0x22, 0x5E, 0x34,
+    0x1C, 0x94, 0xAF, 0x98,
+};
+
+/* rsa_tv_template[3].key, modulus n */
+static const uint8_t rsa4096_n[512] = {
+    0xC3, 0x8B, 0x55, 0x7B, 0x73, 0x4D, 0xFF, 0xE9, 0x9B, 0xC6, 0xDC, 0x67,
+    0x3C, 0xB4, 0x8E, 0xA0, 0x86, 0xED, 0xF2, 0xB9, 0x50, 0x5C, 0x54, 0x5C,
+    0xBA, 0xE4, 0xA1, 0xB2, 0xA7, 0xAE, 0x2F, 0x1B, 0x7D, 0xF1, 0xFB, 0xAC,
+    0x79, 0xC5, 0xDF, 0x1A, 0x00, 0xC9, 0xB2, 0xC1, 0x61, 0x25, 0x33, 0xE6,
+    0x9C, 0xE9, 0xCF, 0xD6, 0x27, 0xC4, 0x4E, 0x44, 0x30, 0x44, 0x5E, 0x08,
+    0xA1, 0x87, 0x52, 0xCC, 0x6B, 0x97, 0x70, 0x8C, 0xBC, 0xA5, 0x06, 0x31,
+    0x0C, 0xD4, 0x2F, 0xD5, 0x7D, 0x26, 0x24, 0xA2, 0xE2, 0xAC, 0x78, 0xF4,
+    0x53, 0x14, 0xCE, 0xF7, 0x19, 0x2E, 0xD7, 0xF7, 0xE6, 0x0C, 0xB9, 0x56,
+    0x7F, 0x0B, 0xF1, 0xB1, 0xE2, 0x43, 0x70, 0xBD, 0x86, 0x1D, 0xA1, 0xCC,
+    0x2B, 0x19, 0x08, 0x76, 0xEF, 0x91, 0xAC, 0xBF, 0x20, 0x24, 0x0D, 0x38,
+    0xC0, 0x89, 0xB8, 0x9A, 0x70, 0xB3, 0x64, 0xD9, 0x8F, 0x80, 0x41, 0x10,
+    0x5B, 0x9F, 0xB1, 0xCB, 0x76, 0x43, 0x00, 0x21, 0x25, 0x36, 0xD4, 0x19,
+    0xFC, 0x55, 0x95, 0x10, 0xE4, 0x26, 0x74, 0x98, 0x2C, 0xD9, 0xBD, 0x0B,
+    0x2B, 0x04, 0xC2, 0xAC, 0x82, 0x38, 0xB4, 0xDD, 0x4C, 0x04, 0x7E, 0x51,
+    0x36, 0x40, 0x1E, 0x0B, 0xC4, 0x7C, 0x25, 0xDD, 0x4B, 0xB2, 0xE7, 0x20,
+    0x0A, 0x57, 0xF9, 0xB4, 0x94, 0xC3, 0x08, 0x33, 0x22, 0x6F, 0x8B, 0x48,
+    0xDB, 0x03, 0x68, 0x5A, 0x5B, 0xBA, 0xAE, 0xF3, 0xAD, 0xCF, 0xC3, 0x6D,
+    0xBA, 0xF1, 0x28, 0x67, 0x7E, 0x6C, 0x79, 0x07, 0xDE, 0xFC, 0xED, 0xE7,
+    0x96, 0xE3, 0x6C, 0xE0, 0x2C, 0x87, 0xF8, 0x02, 0x01, 0x28, 0x38, 0x43,
+    0x21, 0x53, 0x84, 0x69, 0x75, 0x78, 0x15, 0x7E, 0xEE, 0xD2, 0x1B, 0xB9,
+    0x23, 0x40, 0xA8, 0x86, 0x1E, 0x38, 0x83, 0xB2, 0x73, 0x1D, 0x53, 0xFB,
+    0x9E, 0x2A, 0x8A, 0xB2, 0x75, 0x35, 0x01, 0xC3, 0xC3, 0xC4, 0x94, 0xE8,
+    0x84, 0x86, 0x64, 0x81, 0xF4, 0x42, 0xAA, 0x3C, 0x0E, 0xD6, 0x4F, 0xBC,
+    0x0A, 0x09, 0x2D, 0xE7, 0x1B, 0xD4, 0x10, 0xA8, 0x54, 0xEA, 0x89, 0x84,
+    0x8A, 0xCB, 0xF7, 0x5A, 0x3C, 0xCA, 0x76, 0x08, 0x29, 0x62, 0xB4, 0x6A,
+    0x22, 0xDF, 0x14, 0x95, 0x71, 0xFD, 0xB6, 0x86, 0x39, 0xB8, 0x8B, 0xF8,
+    0x91, 0x7F, 0x38, 0xAA, 0x14, 0xCD, 0xE5, 0xF5, 0x1D, 0xC2, 0x6D, 0x53,
+    0x69, 0x52, 0x84, 0x7F, 0xA3, 0x1A, 0x5E, 0x26, 0x04, 0x83, 0x06, 0x73,
+    0x52, 0x56, 0xCF, 0x76, 0x26, 0xC9, 0xDD, 0x75, 0xD7, 0xFC, 0xF4, 0x69,
+    0xD8, 0x7B, 0x55, 0xB7, 0x68, 0x13, 0x53, 0xB9, 0xE7, 0x89, 0xC3, 0xE8,
+    0xD6, 0x6E, 0xA7, 0x6D, 0xEA, 0x81, 0xFD, 0xC4, 0xB7, 0x05, 0x5A, 0xB7,
+    0x41, 0x0A, 0x23, 0x8E, 0x03, 0x8A, 0x1C, 0xAE, 0xD3, 0x1E, 0xCE, 0xE3,
+    0x5E, 0xFC, 0x19, 0x4A, 0xEE, 0x61, 0x9B, 0x8E, 0xE5, 0xE5, 0xDD, 0x85,
+    0xF9, 0x41, 0xEC, 0x14, 0x53, 0x92, 0xF7, 0xDD, 0x06, 0x85, 0x02, 0x91,
+    0xE3, 0xEB, 0x6C, 0x43, 0x03, 0xB1, 0x36, 0x7B, 0x89, 0x5A, 0xA8, 0xEB,
+    0xFC, 0xD5, 0xA8, 0x35, 0xDC, 0x81, 0xD9, 0x5C, 0xBD, 0xCA, 0xDC, 0x9B,
+    0x98, 0x0B, 0x06, 0x5D, 0x0C, 0x5B, 0xEE, 0xF3, 0xD5, 0xCC, 0x57, 0xC9,
+    0x71, 0x2F, 0x90, 0x3B, 0x3C, 0xF0, 0x8E, 0x4E, 0x35, 0x48, 0xAE, 0x63,
+    0x74, 0xA9, 0xFC, 0x72, 0x75, 0x8E, 0x34, 0xA8, 0xF2, 0x1F, 0xEA, 0xDF,
+    0x3A, 0x37, 0x2D, 0xE5, 0x39, 0x39, 0xF8, 0x57, 0x58, 0x3C, 0x04, 0xFE,
+    0x87, 0x06, 0x98, 0xBC, 0x7B, 0xD3, 0x21, 0x36, 0x60, 0x25, 0x54, 0xA7,
+    0x3D, 0xFA, 0x91, 0xCC, 0xA8, 0x0B, 0x92, 0x8E, 0xB4, 0xF7, 0x06, 0xFF,
+    0x1E, 0x95, 0xCB, 0x07, 0x76, 0x97, 0x3B, 0x9D,
+};
+/* rsa_tv_template[3].c */
+static const uint8_t rsa4096_c[512] = {
+    0x5C, 0xCE, 0x9C, 0xD7, 0x9A, 0x9E, 0xA1, 0xFE, 0x7A, 0x82, 0x3C, 0x68,
+    0x27, 0x98, 0xE3, 0x5D, 0xD5, 0xD7, 0x07, 0x29, 0xF5, 0xFB, 0xC3, 0x1A,
+    0x7F, 0x63, 0x1E, 0x62, 0x31, 0x3B, 0x19, 0x87, 0x79, 0x4F, 0xEC, 0x7B,
+    0xF3, 0xCB, 0xEA, 0x9B, 0x95, 0x52, 0x3A, 0x40, 0xE5, 0x87, 0x7B, 0x72,
+    0xD1, 0x72, 0xC9, 0xFB, 0x54, 0x63, 0xD8, 0xC9, 0xD7, 0x2C, 0xFC, 0x7B,
+    0xC3, 0x14, 0x1E, 0xBC, 0x18, 0xB4, 0x34, 0xA1, 0xBF, 0x14, 0xB1, 0x37,
+    0x31, 0x6E, 0xF0, 0x1B, 0x35, 0x19, 0x54, 0x07, 0xF7, 0x99, 0xEC, 0x3E,
+    0x63, 0xE2, 0xCD, 0x61, 0x28, 0x65, 0xC3, 0xCD, 0xB1, 0x38, 0x36, 0xA5,
+    0xB2, 0xD7, 0xB0, 0xDC, 0x1F, 0xF5, 0xEF, 0x19, 0xC7, 0x53, 0x32, 0x2D,
+    0x1C, 0x26, 0xDA, 0xE4, 0x0D, 0xD6, 0x90, 0x7E, 0x28, 0xD8, 0xDC, 0xE4,
+    0x61, 0x05, 0xD2, 0x25, 0x90, 0x01, 0xD3, 0x96, 0x6D, 0xA6, 0xCF, 0x58,
+    0x20, 0xBB, 0x03, 0xF4, 0x01, 0xBC, 0x79, 0xB9, 0x18, 0xD8, 0xB8, 0xBA,
+    0xBD, 0x93, 0xFC, 0xF2, 0x62, 0x5D, 0x8C, 0x66, 0x1E, 0x0E, 0x84, 0x59,
+    0x93, 0xDD, 0xE2, 0x93, 0xA2, 0x62, 0x7D, 0x08, 0x82, 0x7A, 0xDD, 0xFC,
+    0xB8, 0xBC, 0xC5, 0x4F, 0x9C, 0x4E, 0xBF, 0xB4, 0xFC, 0xF4, 0xC5, 0x01,
+    0xE8, 0x00, 0x70, 0x4D, 0x28, 0x26, 0xCC, 0x2E, 0xFE, 0x0E, 0x58, 0x41,
+    0x8B, 0xEC, 0xAF, 0x7C, 0x4B, 0x54, 0xD0, 0xA0, 0x64, 0xF9, 0x32, 0xF4,
+    0x2E, 0x47, 0x65, 0x0A, 0x67, 0x88, 0x39, 0x3A, 0xDB, 0xB2, 0xDB, 0x7B,
+    0xB5, 0xF6, 0x17, 0xA8, 0xD9, 0xC6, 0x5E, 0x28, 0x13, 0x82, 0x8A, 0x99,
+    0xDB, 0x60, 0x08, 0xA5, 0x23, 0x37, 0xFA, 0x88, 0x90, 0x31, 0xC8, 0x9D,
+    0x8F, 0xEC, 0xFB, 0x85, 0x9F, 0xB1, 0xCE, 0xA6, 0x24, 0x50, 0x46, 0x44,
+    0x47, 0xCB, 0x65, 0xD1, 0xDF, 0xC0, 0xB1, 0x6C, 0x90, 0x1F, 0x99, 0x8E,
+    0x4D, 0xD5, 0x9E, 0x31, 0x07, 0x66, 0x87, 0xDF, 0x01, 0xAA, 0x56, 0x3C,
+    0x71, 0xE0, 0x2B, 0x6F, 0x67, 0x3B, 0x23, 0xED, 0xC2, 0xBD, 0x03, 0x30,
+    0x79, 0x76, 0x02, 0x10, 0x10, 0x98, 0x85, 0x8A, 0xFF, 0xFD, 0x0B, 0xDA,
+    0xA5, 0xD9, 0x32, 0x48, 0x02, 0xA0, 0x0B, 0xB9, 0x2A, 0x8A, 0x18, 0xCA,
+    0xC6, 0x8F, 0x3F, 0xBB, 0x16, 0xB2, 0xAA, 0x98, 0x27, 0xE3, 0x60, 0x43,
+    0xED, 0x15, 0x70, 0xD4, 0x57, 0x15, 0xFE, 0x19, 0xD4, 0x9B, 0x13, 0x78,
+    0x8A, 0xF7, 0x21, 0xF1, 0xA2, 0xA2, 0x2D, 0xB3, 0x09, 0xCF, 0x44, 0x91,
+    0x6E, 0x08, 0x3A, 0x30, 0x81, 0x3E, 0x90, 0x93, 0x8A, 0x67, 0x33, 0x00,
+    0x59, 0x54, 0x9A, 0x25, 0xD3, 0x49, 0x8E, 0x9F, 0xC1, 0x4B, 0xE5, 0x86,
+    0xF3, 0x50, 0x4C, 0xBC, 0xC5, 0xD3, 0xF5, 0x3A, 0x54, 0xE1, 0x36, 0x3F,
+    0xE2, 0x5A, 0xB4, 0x37, 0xC0, 0xEB, 0x70, 0x35, 0xEC, 0xF6, 0xB7, 0xE8,
+    0x44, 0x3B, 0x7B, 0xF3, 0xF1, 0xF2, 0x1E, 0xDB, 0x60, 0x7D, 0xD5, 0xBE,
+    0xF0, 0x71, 0x34, 0x90, 0x4C, 0xCB, 0xD4, 0x35, 0x51, 0xC7, 0xDD, 0xD8,
+    0xC9, 0x81, 0xF5, 0x5D, 0x57, 0x46, 0x2C, 0xB1, 0x7B, 0x9B, 0xAA, 0xCB,
+    0xD1, 0x22, 0x25, 0x49, 0x44, 0xA3, 0xD4, 0x6B, 0x29, 0x7B, 0xD8, 0xB2,
+    0x07, 0x93, 0xBF, 0x3D, 0x52, 0x49, 0x84, 0x79, 0xEF, 0xB8, 0xE5, 0xC4,
+    0xAD, 0xCA, 0xA8, 0xC6, 0xF6, 0xA6, 0x76, 0x70, 0x5B, 0x0B, 0xE5, 0x83,
+    0xC6, 0x0E, 0xEF, 0x55, 0xF2, 0xE7, 0xFF, 0x04, 0xEA, 0xE6, 0x13, 0xBE,
+    0x40, 0xE1, 0x40, 0x45, 0x48, 0x66, 0x75, 0x31, 0xAE, 0x35, 0x64, 0x91,
+    0x11, 0x6F, 0xDA, 0xEE, 0x26, 0x86, 0x45, 0x6F, 0x0B, 0xD5, 0x9F, 0x03,
+    0xB1, 0x65, 0x5B, 0xDB, 0xA4, 0xE4, 0xF9, 0x45,
+};
+
+/*
+ * Offset in the scattered buffer of byte 'op_byte' (0 = least significant)
+ * of the operand whose region starts 'region' dwords into each 12-dword
+ * block (0 = exp, 4 = mod, 8 = data). Reproduces the byte layout the ACRY
+ * engine mandates, so the test lays out its DMA input and decodes the
+ * result the same way the hardware does.
+ */
+static int acry_operand_offset(int region, int op_byte)
+{
+    int byte_in_dword;
+    int op_dword;
+    int block;
+    int lane;
+
+    op_dword = op_byte / 4;
+    byte_in_dword = op_byte % 4;
+    block = op_dword / 4;
+    lane = op_dword % 4;
+
+    return (block * 12 + region + lane) * 4 + byte_in_dword;
+}
+
+/*
+ * Write a big-endian (most significant byte first) bignum of 'be_len' bytes
+ * into the scattered buffer region 'region' (exp, mod, or data), placing
+ * significance level k at acry_operand_offset(region, k).
+ */
+static void put_bignum_be_bytes(uint8_t *buf, int region,
+                                const uint8_t *be, int be_len)
+{
+    int be_index;
+    int offset;
+    int k;
+
+    /* be[0] (MSB) maps to the highest level; be_index walks up from 0. */
+    be_index = 0;
+    for (k = be_len - 1; k >= 0; k--) {
+        offset = acry_operand_offset(region, k);
+        buf[offset] = be[be_index++];
+    }
+}
+
+/* Inverse of put_bignum_be_bytes(): gather a big-endian bignum back out. */
+static void get_bignum_be_bytes(const uint8_t *buf, int region,
+                                uint8_t *out_be, int be_len)
+{
+    int be_index;
+    int offset;
+    int k;
+
+    /* Inverse of put_bignum_be_bytes(): highest level -> out_be[0] (MSB). */
+    be_index = 0;
+    for (k = be_len - 1; k >= 0; k--) {
+        offset = acry_operand_offset(region, k);
+        out_be[be_index++] = buf[offset];
+    }
+}
+
+typedef struct AspeedACRYModExp {
+    const char *name;
+    const uint8_t *n;
+    size_t n_len;
+    const uint8_t *e;
+    size_t e_len;
+    const uint8_t *m;
+    size_t m_len;
+    const uint8_t *c;
+    size_t c_len;
+} AspeedACRYModExp;
+
+static const AspeedACRYModExp acry_modexp_tests[] = {
+    {
+        .name = "modexp_rsa2048",
+        .n = rsa2048_n,
+        .n_len = sizeof(rsa2048_n),
+        .e = rsa_e,
+        .e_len = sizeof(rsa_e),
+        .m = rsa_m,
+        .m_len = sizeof(rsa_m),
+        .c = rsa2048_c,
+        .c_len = sizeof(rsa2048_c),
+    },
+    {
+        .name = "modexp_rsa4096",
+        .n = rsa4096_n,
+        .n_len = sizeof(rsa4096_n),
+        .e = rsa_e,
+        .e_len = sizeof(rsa_e),
+        .m = rsa_m,
+        .m_len = sizeof(rsa_m),
+        .c = rsa4096_c,
+        .c_len = sizeof(rsa4096_c),
+    },
+};
+
+typedef struct AspeedACRYTest {
+    const char *machine;
+    uint64_t dram_addr;
+    uint64_t sram_addr;
+    uint64_t acry_addr;
+    int index;
+} AspeedACRYTest;
+
+static void test_modexp_rsa(const void *opaque)
+{
+    const AspeedACRYTest *c = opaque;
+    const AspeedACRYModExp *t = &acry_modexp_tests[c->index];
+    QTestState *qts = qtest_init(c->machine);
+    uint8_t dram_buf[ACRY_SRAM_SIZE] = { 0 };
+    uint8_t sram_buf[ACRY_SRAM_SIZE] = { 0 };
+    uint8_t result[ACRY_MAX_BYTES] = { 0 };
+
+    g_assert_cmpuint(t->c_len, <=, sizeof(result));
+
+    put_bignum_be_bytes(dram_buf, ACRY_EXP_OFFSET, t->e, t->e_len);
+    put_bignum_be_bytes(dram_buf, ACRY_MOD_OFFSET, t->n, t->n_len);
+    put_bignum_be_bytes(dram_buf, ACRY_DATA_OFFSET, t->m, t->m_len);
+
+    qtest_memwrite(qts, c->dram_addr, dram_buf, sizeof(dram_buf));
+
+    qtest_writel(qts, c->acry_addr + ACRY_DMA_CMD, ACRY_DMA_CMD_DMEM_AHB);
+    qtest_writel(qts, c->acry_addr + ACRY_DMA_SRC, c->dram_addr);
+    qtest_writel(qts, c->acry_addr + ACRY_RSA_KEY_LEN,
+                ((uint32_t)(t->e_len * 8) << 16) | (uint32_t)(t->n_len * 8));
+    qtest_writel(qts, c->acry_addr + ACRY_DMA_LEN, ACRY_SRAM_SIZE);
+    qtest_writel(qts, c->acry_addr + ACRY_INT_MASK,
+                ACRY_INT_MASK_RSA_ENG_MASK | ACRY_INT_MASK_RSA_DMA_MASK);
+    qtest_writel(qts, c->acry_addr + ACRY_DMA_CMD, ACRY_DMA_CMD_SRAM_MODE_RSA);
+    qtest_writel(qts, c->acry_addr + ACRY_TRIGGER,
+                ACRY_TRIGGER_RSA_START | ACRY_TRIGGER_RSA_DMA_DATA);
+
+    /* Completion requires both RSA_ENG_DONE and RSA_DMA_DONE to be asserted. */
+    g_assert_cmphex(qtest_readl(qts, c->acry_addr + ACRY_STATUS), ==,
+                    ACRY_STATUS_RSA_DONE);
+
+    qtest_memread(qts, c->sram_addr, sram_buf, sizeof(sram_buf));
+    get_bignum_be_bytes(sram_buf, ACRY_DATA_OFFSET, result, t->c_len);
+    g_assert_cmpmem(result, t->c_len, t->c, t->c_len);
+
+    /* Clear IRQ status and check it is deasserted */
+    qtest_writel(qts, c->acry_addr + ACRY_STATUS, ACRY_STATUS_RSA_DONE);
+    g_assert_cmphex(qtest_readl(qts, c->acry_addr + ACRY_STATUS), ==, 0);
+
+    qtest_quit(qts);
+}
+
+static void aspeed_add_acry_tests(const char *prefix, const char *machine,
+                                  uint64_t acry_addr, uint64_t sram_addr,
+                                  uint64_t dram_addr)
+{
+    QCryptoAkCipherOptions opts = {
+        .alg = QCRYPTO_AK_CIPHER_ALGO_RSA,
+        .u.rsa.padding_alg = QCRYPTO_RSA_PADDING_ALGO_RAW,
+    };
+    int i;
+
+    if (!qcrypto_akcipher_supports(&opts)) {
+        g_printerr("# skip ACRY tests: raw RSA not supported by the crypto "
+                   "backend\n");
+        return;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(acry_modexp_tests); i++) {
+        g_autofree char *path = NULL;
+        AspeedACRYTest *t;
+
+        path = g_strdup_printf("%s/acry/%s", prefix,
+                               acry_modexp_tests[i].name);
+        t = g_new0(AspeedACRYTest, 1);
+        t->machine = machine;
+        t->acry_addr = acry_addr;
+        t->sram_addr = sram_addr;
+        t->dram_addr = dram_addr;
+        t->index = i;
+        qtest_add_data_func_full(path, t, test_modexp_rsa, g_free);
+    }
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+
+    aspeed_add_acry_tests("ast2600", "-machine ast2600-evb",
+                          0x1e6fa000, 0x1e710000, 0x80001000);
+
+    return g_test_run();
+}
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index f7c7d06620..c58be94c25 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -220,7 +220,8 @@ qtests_npcm7xx = \
 qtests_npcm8xx = \
   ['npcm_gmac-test']
 qtests_aspeed = \
-  ['aspeed_gpio-test',
+  ['aspeed-acry-test',
+   'aspeed_gpio-test',
    'aspeed_hace-test',
    'aspeed_scu-test',
    'aspeed_smc-test']
@@ -392,6 +393,8 @@ if get_option('replication').allowed()
 endif
 
 qtests = {
+  'aspeed-acry-test': [files('aspeed-acry-test.c'),
+                       crypto],
   'aspeed_hace-test': [files('aspeed-hace-utils.c', 'aspeed_hace-test.c'),
                        crypto],
   'aspeed_smc-test': files('aspeed-smc-utils.c', 'aspeed_smc-test.c'),
-- 
2.53.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.