RE: [PATCH v2 04/17] hw/misc/aspeed_hace: Support the CTR mode for the crypto command
Kane Chen <[email protected]>
| Newsgroups | org.nongnu.qemu-arm,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <SI6PR06MB763107A6DB1D80EB841EE731F7DE2@SI6PR06MB7631.apcprd06.prod.outlook.com> |
> -----Original Message----- > From: Jamin Lin <[email protected]> > Sent: Wednesday, July 15, 2026 11:33 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 04/17] hw/misc/aspeed_hace: Support the CTR mode for > the crypto command > > The AST2600, AST1030 and later crypto engines add AES/DES/3DES CTR mode > (HACE10[6:4] = 0b100) on top of the ECB/CBC modes shared with the AST2500. > Decode the CTR selection, round the working buffers up to a whole block so the > stream-like final block is still processed a block at a time, and write the > counter advanced by the number of blocks consumed back to the context > buffer so the driver can continue across requests. > > Signed-off-by: Jamin Lin <[email protected]> > --- > hw/misc/aspeed_hace.c | 50 > ++++++++++++++++++++++++++++++++++++++----- > 1 file changed, 45 insertions(+), 5 deletions(-) > > diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index > 3d3f1fc8dd..09d0515271 100644 > --- a/hw/misc/aspeed_hace.c > +++ b/hw/misc/aspeed_hace.c > @@ -42,6 +42,7 @@ > #define CRYPT_CMD_OP_MODE_MASK (0x7 << 4) > #define CRYPT_CMD_ECB (0x0 << 4) > #define CRYPT_CMD_CBC (0x1 << 4) > +#define CRYPT_CMD_CTR (0x4 << 4) > /* AES key length HACE10[3:2] */ > #define CRYPT_CMD_AES_KEY_LEN_MASK (0x3 << 2) > #define CRYPT_CMD_AES256 (0x2 << 2) > @@ -589,6 +590,9 @@ static bool crypt_decode_cmd(uint32_t cmd, > QCryptoCipherAlgo *alg, > case CRYPT_CMD_CBC: > *mode = QCRYPTO_CIPHER_MODE_CBC; > break; > + case CRYPT_CMD_CTR: > + *mode = QCRYPTO_CIPHER_MODE_CTR; > + break; > default: > return false; > } > @@ -652,6 +656,22 @@ static bool crypt_prepare_sg(AspeedHACEState *s, > uint64_t addr, > return copied == len; > } > > +/* > + * Add @add to the big-endian counter block @ctr (@len bytes) in place, > +so the > + * CTR mode counter can be advanced by the number of blocks just > consumed. > + */ > +static void crypt_be_add(uint8_t *ctr, size_t len, uint64_t add) { > + size_t i = len; > + > + while (i > 0 && add) { > + i--; > + add += ctr[i]; > + ctr[i] = add & 0xff; > + add >>= 8; > + } > +} > + > /* > * Perform an AES/DES/3DES ECB/CBC operation. The source and destination > are > * either single contiguous buffers (direct access mode) or scatter-gather > @@ -677,6 +697,7 @@ static void do_crypt_operation(AspeedHACEState *s, > uint32_t cmd) > uint64_t dst_addr; > size_t iv_offset; > size_t blocklen; > + size_t buf_len; > size_t keylen; > bool status; > > @@ -729,8 +750,14 @@ static void do_crypt_operation(AspeedHACEState *s, > uint32_t cmd) > return; > } > > - src_buf = g_malloc0(len); > - dst_buf = g_malloc0(len); > + /* > + * Round the working buffers up to a whole block. Block modes are > already > + * block-aligned; the stream-like CTR mode may leave a partial final > block > + * that the engine still processes a full block at a time. > + */ > + buf_len = QEMU_ALIGN_UP(len, blocklen); > + src_buf = g_malloc0(buf_len); > + dst_buf = g_malloc0(buf_len); > > /* Gather the source into the bounce buffer, per the selected mode. */ > src_addr = s->regs[R_CRYPT_SRC]; > @@ -751,7 +778,7 @@ static void do_crypt_operation(AspeedHACEState *s, > uint32_t cmd) > } > > if (encrypt) { > - if (qcrypto_cipher_encrypt(cipher, src_buf, dst_buf, len, > + if (qcrypto_cipher_encrypt(cipher, src_buf, dst_buf, buf_len, > &local_err) < 0) { > qemu_log_mask(LOG_GUEST_ERROR, "%s: encrypt failed: > %s\n", > __func__, error_get_pretty(local_err)); @@ > -759,7 +786,7 @@ static void do_crypt_operation(AspeedHACEState *s, > uint32_t cmd) > return; > } > } else { > - if (qcrypto_cipher_decrypt(cipher, src_buf, dst_buf, len, > + if (qcrypto_cipher_decrypt(cipher, src_buf, dst_buf, buf_len, > &local_err) < 0) { > qemu_log_mask(LOG_GUEST_ERROR, "%s: decrypt failed: > %s\n", > __func__, error_get_pretty(local_err)); @@ > -792,13 +819,26 @@ static void do_crypt_operation(AspeedHACEState *s, > uint32_t cmd) > * output when encrypting, or of the input when decrypting. Write > it > * back as the IV for the next request. > */ > - next_iv = (encrypt ? dst_buf : src_buf) + len - blocklen; > + next_iv = (encrypt ? dst_buf : src_buf) + buf_len - blocklen; > if (address_space_write(&s->dram_as, ctx_addr + iv_offset, > MEMTXATTRS_UNSPECIFIED, next_iv, > blocklen)) { > qemu_log_mask(LOG_GUEST_ERROR, > "%s: Failed to write IV, addr=0x%" > HWADDR_PRIx "\n", > __func__, ctx_addr + iv_offset); > } > + } else if (mode == QCRYPTO_CIPHER_MODE_CTR) { > + /* > + * CTR chains on the counter, which advances by one per block. > Add the > + * number of blocks processed (buf_len / blocklen) and write it > back. > + */ > + crypt_be_add(ctx + iv_offset, blocklen, buf_len / blocklen); > + if (address_space_write(&s->dram_as, ctx_addr + iv_offset, > + MEMTXATTRS_UNSPECIFIED, ctx + > iv_offset, > + blocklen)) { > + qemu_log_mask(LOG_GUEST_ERROR, > + "%s: Failed to write IV, addr=0x%" > HWADDR_PRIx "\n", > + __func__, ctx_addr + iv_offset); > + } > } > } > > -- > 2.43.0 Reviewed-by: Kane Chen <[email protected]>