> -----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]>

Reply via email to