From 4025a2f8b93d5a745fdadfe0171c3f199e735e17 Mon Sep 17 00:00:00 2001 From: "harshal.patil" Date: Wed, 19 Aug 2026 11:27:42 +0530 Subject: [PATCH] fix(mbedtls/aes): fix ESP32-S2 Crypto DMA stall on PSRAM output with partial blocks The ESP32-S2 Crypto DMA in-channel stalls silently when a receive descriptor list transitions from external to internal RAM. The AES driver hits this when a PSRAM-output operation has a trailing partial block, as the internal stream descriptor is linked after the external RAM data descriptors. - esp_aes_process_dma(): process the block-aligned part and the partial block as two separate DMA operations, keeping each descriptor list uniform - crypto_dma_ll_reset(): also reset the in-channel (per the TRM receive reset sequence), otherwise stale state from a preceding external-RAM operation corrupts the next operation's output The GCM DMA path is unaffected; it never operates on PSRAM buffers. --- .../esp32s2/include/hal/crypto_dma_ll.h | 4 ++-- .../mbedtls/port/aes/dma/esp_aes_dma_core.c | 20 +++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/components/esp_hal_security/esp32s2/include/hal/crypto_dma_ll.h b/components/esp_hal_security/esp32s2/include/hal/crypto_dma_ll.h index 10f64537f85..1b3f31a32d1 100644 --- a/components/esp_hal_security/esp32s2/include/hal/crypto_dma_ll.h +++ b/components/esp_hal_security/esp32s2/include/hal/crypto_dma_ll.h @@ -68,8 +68,8 @@ static inline void crypto_dma_ll_reset_register(void) */ static inline void crypto_dma_ll_reset(void) { - SET_PERI_REG_MASK(CRYPTO_DMA_CONF0_REG, CONF0_REG_AHBM_RST | CONF0_REG_OUT_RST | CONF0_REG_AHBM_FIFO_RST); - CLEAR_PERI_REG_MASK(CRYPTO_DMA_CONF0_REG, CONF0_REG_AHBM_RST | CONF0_REG_OUT_RST | CONF0_REG_AHBM_FIFO_RST); + SET_PERI_REG_MASK(CRYPTO_DMA_CONF0_REG, CONF0_REG_AHBM_RST | CONF0_REG_IN_RST | CONF0_REG_OUT_RST | CONF0_REG_AHBM_FIFO_RST); + CLEAR_PERI_REG_MASK(CRYPTO_DMA_CONF0_REG, CONF0_REG_AHBM_RST | CONF0_REG_IN_RST | CONF0_REG_OUT_RST | CONF0_REG_AHBM_FIFO_RST); } /** diff --git a/components/mbedtls/port/aes/dma/esp_aes_dma_core.c b/components/mbedtls/port/aes/dma/esp_aes_dma_core.c index bc2b2e586dc..386de1edec7 100644 --- a/components/mbedtls/port/aes/dma/esp_aes_dma_core.c +++ b/components/mbedtls/port/aes/dma/esp_aes_dma_core.c @@ -1057,6 +1057,26 @@ int esp_aes_process_dma(esp_aes_context *ctx, const unsigned char *input, unsign return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH; } +#if SOC_AES_CRYPTO_DMA && CONFIG_SPIRAM + /* The Crypto DMA in-channel stalls indefinitely (no descriptor error is raised) when a + receive descriptor list transitions from a buffer in external RAM to one in internal + RAM. Avoid linking the internal stream buffer descriptor after external-RAM data + descriptors by processing the block-aligned part and the trailing partial block as + two separate DMA operations. */ + if (block_bytes > 0 && stream_bytes > 0 && esp_ptr_external_ram(output)) { + ret = esp_aes_process_dma(ctx, input, output, block_bytes, NULL); + if (ret != 0) { + mbedtls_platform_zeroize(output, len); + return ret; + } + ret = esp_aes_process_dma(ctx, input + block_bytes, output + block_bytes, stream_bytes, stream_out); + if (ret != 0) { + mbedtls_platform_zeroize(output, len); + } + return ret; + } +#endif /* SOC_AES_CRYPTO_DMA && CONFIG_SPIRAM */ + if (block_bytes > 0) { /* Flush cache if input in external ram */ #if (CONFIG_SPIRAM && SOC_PSRAM_DMA_CAPABLE)