mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-11-04 06:11:06 +00:00 
			
		
		
		
	aes/sha: use a shared lazy allocated GDMA channel for AES and SHA
Removed the old dynamically allocated GDMA channel approach. It proved too unreliable as we couldn't not ensure consumers of the mbedtls would properly free the channels after use. Replaced by a single shared GDMA channel for AES and SHA, which won't be released unless user specifically calls API for releasing it.
This commit is contained in:
		@@ -54,8 +54,8 @@
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if SOC_AES_GDMA
 | 
			
		||||
#define AES_LOCK() esp_crypto_aes_lock_acquire()
 | 
			
		||||
#define AES_RELEASE() esp_crypto_aes_lock_release()
 | 
			
		||||
#define AES_LOCK() esp_crypto_sha_aes_lock_acquire()
 | 
			
		||||
#define AES_RELEASE() esp_crypto_sha_aes_lock_release()
 | 
			
		||||
#elif SOC_AES_CRYPTO_DMA
 | 
			
		||||
#define AES_LOCK() esp_crypto_dma_lock_acquire()
 | 
			
		||||
#define AES_RELEASE() esp_crypto_dma_lock_release()
 | 
			
		||||
 
 | 
			
		||||
@@ -11,157 +11,16 @@
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
#include "esp_aes_dma_priv.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/lock.h>
 | 
			
		||||
 | 
			
		||||
#include "freertos/FreeRTOS.h"
 | 
			
		||||
#include "freertos/task.h"
 | 
			
		||||
 | 
			
		||||
#include "driver/periph_ctrl.h"
 | 
			
		||||
#include "hal/gdma_ll.h"
 | 
			
		||||
#include "soc/soc_caps.h"
 | 
			
		||||
#include "esp_private/gdma.h"
 | 
			
		||||
#include "esp_log.h"
 | 
			
		||||
 | 
			
		||||
#define NEW_CHANNEL_TIMEOUT_MS  1000
 | 
			
		||||
#define NEW_CHANNEL_DELAY_MS    100
 | 
			
		||||
 | 
			
		||||
static const char *TAG = "esp_aes_gdma";
 | 
			
		||||
 | 
			
		||||
static _lock_t gdma_ch_lock;
 | 
			
		||||
/* For GDMA we allocate and reserve a single DMA pair for AES at esp_aes_init
 | 
			
		||||
   and release it esp_aes_free
 | 
			
		||||
   This is done to avoid the GDMA associated overhead when doing multiple AES transforms in a row.
 | 
			
		||||
 | 
			
		||||
    The channel is shared between any AES operations that are running in parallel,
 | 
			
		||||
    access will be limited by the peripheral lock
 | 
			
		||||
 */
 | 
			
		||||
static uint8_t ref_counts;
 | 
			
		||||
 | 
			
		||||
/* The GDMA channel is protected from concurrent access by the general AES peripheral lock */
 | 
			
		||||
static gdma_channel_handle_t tx_channel;
 | 
			
		||||
static gdma_channel_handle_t rx_channel;
 | 
			
		||||
 | 
			
		||||
/* Allocate a new GDMA channel, will keep trying until NEW_CHANNEL_TIMEOUT_MS */
 | 
			
		||||
static inline esp_err_t esp_aes_gdma_new_channel(gdma_channel_alloc_config_t *channel_config, gdma_channel_handle_t *channel)
 | 
			
		||||
{
 | 
			
		||||
    esp_err_t ret;
 | 
			
		||||
    int time_waited_ms = 0;
 | 
			
		||||
 | 
			
		||||
    while(1) {
 | 
			
		||||
        ret = gdma_new_channel(channel_config, channel);
 | 
			
		||||
 | 
			
		||||
        if (ret == ESP_OK) {
 | 
			
		||||
            break;
 | 
			
		||||
        } else if (time_waited_ms >= NEW_CHANNEL_TIMEOUT_MS) {
 | 
			
		||||
            *channel = NULL;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        time_waited_ms += NEW_CHANNEL_DELAY_MS;
 | 
			
		||||
        vTaskDelay(NEW_CHANNEL_DELAY_MS / portTICK_PERIOD_MS);
 | 
			
		||||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Initialize GDMA module and channels */
 | 
			
		||||
static inline void esp_aes_gdma_init(void)
 | 
			
		||||
{
 | 
			
		||||
    esp_err_t ret;
 | 
			
		||||
 | 
			
		||||
    gdma_channel_alloc_config_t channel_config = {
 | 
			
		||||
        .direction = GDMA_CHANNEL_DIRECTION_TX,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    ret = esp_aes_gdma_new_channel(&channel_config, &tx_channel);
 | 
			
		||||
    if (ret != ESP_OK) {
 | 
			
		||||
        goto err;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    channel_config.direction = GDMA_CHANNEL_DIRECTION_RX;
 | 
			
		||||
    ret = esp_aes_gdma_new_channel(&channel_config, &rx_channel);
 | 
			
		||||
    if (ret != ESP_OK) {
 | 
			
		||||
        gdma_del_channel(tx_channel); // Clean up already allocated TX channel
 | 
			
		||||
        goto err;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    gdma_connect(tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_AES, 0));
 | 
			
		||||
    gdma_connect(rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_AES, 0));
 | 
			
		||||
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
err:
 | 
			
		||||
    /* mbedtls_aes_init do not have a way of signaling errors to the caller
 | 
			
		||||
       so we set the channel to NULL and detect it in esp_aes_dma_start */
 | 
			
		||||
    ESP_LOGE(TAG, "Failed to acquire DMA channel, Err=0x%X", ret);
 | 
			
		||||
    tx_channel = NULL;
 | 
			
		||||
    rx_channel = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void esp_aes_dma_init()
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    _lock_acquire(&gdma_ch_lock);
 | 
			
		||||
    if (ref_counts == 0) {
 | 
			
		||||
        esp_aes_gdma_init();
 | 
			
		||||
    }
 | 
			
		||||
    ref_counts++;
 | 
			
		||||
    _lock_release(&gdma_ch_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void esp_aes_gdma_free(void)
 | 
			
		||||
{
 | 
			
		||||
    gdma_disconnect(tx_channel);
 | 
			
		||||
    gdma_disconnect(rx_channel);
 | 
			
		||||
    gdma_del_channel(tx_channel);
 | 
			
		||||
    gdma_del_channel(rx_channel);
 | 
			
		||||
 | 
			
		||||
    tx_channel = NULL;
 | 
			
		||||
    rx_channel = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void esp_aes_dma_free()
 | 
			
		||||
{
 | 
			
		||||
    _lock_acquire(&gdma_ch_lock);
 | 
			
		||||
    ref_counts--;
 | 
			
		||||
    if (ref_counts == 0) {
 | 
			
		||||
        esp_aes_gdma_free();
 | 
			
		||||
    }
 | 
			
		||||
    _lock_release(&gdma_ch_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#include "esp_crypto_shared_gdma.h"
 | 
			
		||||
 | 
			
		||||
esp_err_t esp_aes_dma_start(const lldesc_t *input, const lldesc_t *output)
 | 
			
		||||
{
 | 
			
		||||
#if SOC_GDMA_SUPPORT_EXTMEM
 | 
			
		||||
    int tx_ch_id = 0;
 | 
			
		||||
    int rx_ch_id = 0;
 | 
			
		||||
#endif //SOC_GDMA_SUPPORT_EXTMEM
 | 
			
		||||
 | 
			
		||||
    if (!tx_channel || !rx_channel) {
 | 
			
		||||
        /* Will happen if no channel was acquired before timeout */
 | 
			
		||||
        return ESP_FAIL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#if SOC_GDMA_SUPPORT_EXTMEM
 | 
			
		||||
    gdma_get_channel_id(tx_channel, &tx_ch_id);
 | 
			
		||||
    gdma_get_channel_id(rx_channel, &rx_ch_id);
 | 
			
		||||
    /* An L2 FIFO bigger than 40 bytes is need when accessing external ram */
 | 
			
		||||
    gdma_ll_tx_extend_fifo_size_to(&GDMA, tx_ch_id, 40);
 | 
			
		||||
    gdma_ll_rx_extend_l2_fifo_size_to(&GDMA, rx_ch_id, 40);
 | 
			
		||||
    gdma_ll_tx_set_block_size_psram(&GDMA, tx_ch_id, GDMA_OUT_EXT_MEM_BK_SIZE_16B);
 | 
			
		||||
    gdma_ll_rx_set_block_size_psram(&GDMA, rx_ch_id, GDMA_OUT_EXT_MEM_BK_SIZE_16B);
 | 
			
		||||
#endif //SOC_GDMA_SUPPORT_EXTMEM
 | 
			
		||||
 | 
			
		||||
    gdma_start(tx_channel, (intptr_t)input);
 | 
			
		||||
    gdma_start(rx_channel, (intptr_t)output);
 | 
			
		||||
 | 
			
		||||
    return ESP_OK;
 | 
			
		||||
    return esp_crypto_shared_gdma_start(input, output, GDMA_TRIG_PERIPH_AES);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool esp_aes_dma_done(const lldesc_t *output)
 | 
			
		||||
{
 | 
			
		||||
    return (output->owner == 0);
 | 
			
		||||
 
 | 
			
		||||
@@ -22,27 +22,6 @@
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if SOC_AES_GDMA
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Initialize the GDMA channel
 | 
			
		||||
 *
 | 
			
		||||
 * @note Allocate and initialize a DMA channel (rx and tx) for the AES peripheral
 | 
			
		||||
 *       Only one channel will be initialized at any given time. If two or more AES operations are
 | 
			
		||||
 *       run in parallel the channel will be shared sequentially.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
void esp_aes_dma_init(void);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Free the GDMA channel
 | 
			
		||||
 *
 | 
			
		||||
 * @note The channel will only be freed if there are no other AES operations currently using it
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
void esp_aes_dma_free(void);
 | 
			
		||||
#endif //SOC_AES_GDMA
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Start the DMA engine
 | 
			
		||||
 *
 | 
			
		||||
 
 | 
			
		||||
@@ -54,10 +54,6 @@ bool valid_key_length(const esp_aes_context *ctx)
 | 
			
		||||
void esp_aes_init( esp_aes_context *ctx )
 | 
			
		||||
{
 | 
			
		||||
    bzero( ctx, sizeof( esp_aes_context ) );
 | 
			
		||||
 | 
			
		||||
#if SOC_AES_GDMA
 | 
			
		||||
    esp_aes_dma_init();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void esp_aes_free( esp_aes_context *ctx )
 | 
			
		||||
@@ -66,10 +62,6 @@ void esp_aes_free( esp_aes_context *ctx )
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#if SOC_AES_GDMA
 | 
			
		||||
    esp_aes_dma_free();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    bzero( ctx, sizeof( esp_aes_context ) );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,170 @@
 | 
			
		||||
// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
#include "esp_crypto_shared_gdma.h"
 | 
			
		||||
 | 
			
		||||
#include "freertos/FreeRTOS.h"
 | 
			
		||||
#include "freertos/task.h"
 | 
			
		||||
 | 
			
		||||
#include "hal/gdma_ll.h"
 | 
			
		||||
#include "soc/soc_caps.h"
 | 
			
		||||
#include "esp_log.h"
 | 
			
		||||
#include "esp_err.h"
 | 
			
		||||
#include "esp_crypto_lock.h"
 | 
			
		||||
 | 
			
		||||
#define NEW_CHANNEL_TIMEOUT_MS  1000
 | 
			
		||||
#define NEW_CHANNEL_DELAY_MS    100
 | 
			
		||||
 | 
			
		||||
static const char *TAG = "crypto_shared_gdma";
 | 
			
		||||
 | 
			
		||||
static gdma_channel_handle_t rx_channel;
 | 
			
		||||
static gdma_channel_handle_t tx_channel;
 | 
			
		||||
 | 
			
		||||
/* Allocate a new GDMA channel, will keep trying until NEW_CHANNEL_TIMEOUT_MS */
 | 
			
		||||
static inline esp_err_t crypto_shared_gdma_new_channel(gdma_channel_alloc_config_t *channel_config, gdma_channel_handle_t *channel)
 | 
			
		||||
{
 | 
			
		||||
    esp_err_t ret;
 | 
			
		||||
    int time_waited_ms = 0;
 | 
			
		||||
 | 
			
		||||
    while(1) {
 | 
			
		||||
        ret = gdma_new_channel(channel_config, channel);
 | 
			
		||||
 | 
			
		||||
        if (ret == ESP_OK) {
 | 
			
		||||
            break;
 | 
			
		||||
        } else if (time_waited_ms >= NEW_CHANNEL_TIMEOUT_MS) {
 | 
			
		||||
            *channel = NULL;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        time_waited_ms += NEW_CHANNEL_DELAY_MS;
 | 
			
		||||
        vTaskDelay(NEW_CHANNEL_DELAY_MS / portTICK_PERIOD_MS);
 | 
			
		||||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if SOC_GDMA_SUPPORT_EXTMEM
 | 
			
		||||
/* Initialize external memory specific DMA configs */
 | 
			
		||||
static void esp_crypto_shared_dma_init_extmem(void)
 | 
			
		||||
{
 | 
			
		||||
    int tx_ch_id = 0;
 | 
			
		||||
    int rx_ch_id = 0;
 | 
			
		||||
 | 
			
		||||
    gdma_get_channel_id(tx_channel, &tx_ch_id);
 | 
			
		||||
    gdma_get_channel_id(rx_channel, &rx_ch_id);
 | 
			
		||||
 | 
			
		||||
    /* An L2 FIFO bigger than 40 bytes is need when accessing external ram */
 | 
			
		||||
    gdma_ll_tx_extend_fifo_size_to(&GDMA, tx_ch_id, 40);
 | 
			
		||||
    gdma_ll_rx_extend_l2_fifo_size_to(&GDMA, rx_ch_id, 40);
 | 
			
		||||
    gdma_ll_tx_set_block_size_psram(&GDMA, tx_ch_id, GDMA_OUT_EXT_MEM_BK_SIZE_16B);
 | 
			
		||||
    gdma_ll_rx_set_block_size_psram(&GDMA, rx_ch_id, GDMA_OUT_EXT_MEM_BK_SIZE_16B);
 | 
			
		||||
}
 | 
			
		||||
#endif //SOC_GDMA_SUPPORT_EXTMEM
 | 
			
		||||
 | 
			
		||||
/* Initialize GDMA module and channels */
 | 
			
		||||
static esp_err_t crypto_shared_gdma_init(void)
 | 
			
		||||
{
 | 
			
		||||
    esp_err_t ret;
 | 
			
		||||
 | 
			
		||||
    gdma_channel_alloc_config_t channel_config_tx = {
 | 
			
		||||
        .direction = GDMA_CHANNEL_DIRECTION_TX,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    gdma_channel_alloc_config_t channel_config_rx = {
 | 
			
		||||
        .direction = GDMA_CHANNEL_DIRECTION_RX,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    ret = crypto_shared_gdma_new_channel(&channel_config_tx, &tx_channel);
 | 
			
		||||
    if (ret != ESP_OK) {
 | 
			
		||||
        goto err;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = crypto_shared_gdma_new_channel(&channel_config_rx, &rx_channel);
 | 
			
		||||
    if (ret != ESP_OK) {
 | 
			
		||||
        gdma_del_channel(tx_channel); // Clean up already allocated TX channel
 | 
			
		||||
        goto err;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#if SOC_GDMA_SUPPORT_EXTMEM
 | 
			
		||||
    esp_crypto_shared_dma_init_extmem();
 | 
			
		||||
#endif //SOC_GDMA_SUPPORT_EXTMEM
 | 
			
		||||
 | 
			
		||||
    gdma_connect(rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_AES, 0));
 | 
			
		||||
    gdma_connect(tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_AES, 0));
 | 
			
		||||
 | 
			
		||||
    return ESP_OK;
 | 
			
		||||
 | 
			
		||||
err:
 | 
			
		||||
    ESP_LOGE(TAG, "Failed to acquire DMA channel, Err=0x%X", ret);
 | 
			
		||||
    tx_channel = NULL;
 | 
			
		||||
    rx_channel = NULL;
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
esp_err_t esp_crypto_shared_gdma_start(const lldesc_t *input, const lldesc_t *output, gdma_trigger_peripheral_t peripheral)
 | 
			
		||||
{
 | 
			
		||||
    int rx_ch_id = 0;
 | 
			
		||||
    esp_err_t ret = ESP_OK;
 | 
			
		||||
 | 
			
		||||
    if (tx_channel == NULL) {
 | 
			
		||||
        /* Allocate a pair of RX and TX for crypto, should only happen the first time we use the GMDA
 | 
			
		||||
           or if user called esp_crypto_shared_gdma_release */
 | 
			
		||||
        ret = crypto_shared_gdma_init();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (ret != ESP_OK) {
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Tx channel is shared between AES and SHA, need to connect to peripheral every time */
 | 
			
		||||
    gdma_disconnect(tx_channel);
 | 
			
		||||
 | 
			
		||||
    if (peripheral == GDMA_TRIG_PERIPH_SHA) {
 | 
			
		||||
        gdma_connect(tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SHA, 0));
 | 
			
		||||
    } else if (peripheral == GDMA_TRIG_PERIPH_AES) {
 | 
			
		||||
        gdma_connect(tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_AES, 0));
 | 
			
		||||
    } else {
 | 
			
		||||
        return ESP_ERR_INVALID_ARG;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* tx channel is reset by gdma_connect(), also reset rx to ensure a known state */
 | 
			
		||||
    gdma_get_channel_id(tx_channel, &rx_ch_id);
 | 
			
		||||
    gdma_ll_rx_reset_channel(&GDMA, rx_ch_id);
 | 
			
		||||
 | 
			
		||||
    gdma_start(tx_channel, (intptr_t)input);
 | 
			
		||||
    gdma_start(rx_channel, (intptr_t)output);
 | 
			
		||||
 | 
			
		||||
    return ESP_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void esp_crypto_shared_gdma_free()
 | 
			
		||||
{
 | 
			
		||||
    esp_crypto_sha_aes_lock_acquire();
 | 
			
		||||
 | 
			
		||||
    if (rx_channel != NULL) {
 | 
			
		||||
        gdma_disconnect(rx_channel);
 | 
			
		||||
        gdma_del_channel(rx_channel);
 | 
			
		||||
        rx_channel = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (tx_channel != NULL) {
 | 
			
		||||
        gdma_disconnect(tx_channel);
 | 
			
		||||
        gdma_del_channel(tx_channel);
 | 
			
		||||
        tx_channel = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    esp_crypto_sha_aes_lock_release();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										55
									
								
								components/mbedtls/port/include/esp_crypto_shared_gdma.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								components/mbedtls/port/include/esp_crypto_shared_gdma.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
			
		||||
// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "soc/lldesc.h"
 | 
			
		||||
#include "esp_private/gdma.h"
 | 
			
		||||
#include "esp_err.h"
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Start a GDMA transfer on the shared crypto DMA channel
 | 
			
		||||
 *
 | 
			
		||||
 * @note Will allocate a GDMA channel for AES & SHA if no such channel is already allocated
 | 
			
		||||
 *
 | 
			
		||||
 * @param input Input linked list descriptor
 | 
			
		||||
 * @param output Output linked list descriptor
 | 
			
		||||
 * @param peripheral Crypto peripheral to connect the DMA to, either GDMA_TRIG_PERIPH_AES or
 | 
			
		||||
 *                   GDMA_TRIG_PERIPH_SHA
 | 
			
		||||
 * @return esp_err_t ESP_FAIL if no GDMA channel available
 | 
			
		||||
 */
 | 
			
		||||
esp_err_t esp_crypto_shared_gdma_start(const lldesc_t *input, const lldesc_t *output, gdma_trigger_peripheral_t peripheral);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Frees any shared crypto DMA channel, if esp_crypto_shared_gdma_start is called after
 | 
			
		||||
 *        this, new GDMA channels will be allocated.
 | 
			
		||||
 *
 | 
			
		||||
 * @note Function is meant to be called from user code, and thus takes AES/SHA lock.
 | 
			
		||||
 *       This means this function should not be called from code which already takes these locks,
 | 
			
		||||
 *       i.e. inside our AES/SHA code.
 | 
			
		||||
 *
 | 
			
		||||
 *       If you are continously using AES/SHA (e.g. because of a wifi connection) then it's not recommended
 | 
			
		||||
 *       to use this API. Freeing the channel is mainly for use cases where you are finished with the crypto peripherals
 | 
			
		||||
 *       and need the DMA channel for other peripherals. An example would be doing some processing after disconnecting WiFi
 | 
			
		||||
 */
 | 
			
		||||
void esp_crypto_shared_gdma_free(void);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
@@ -47,10 +47,6 @@
 | 
			
		||||
 | 
			
		||||
#include "sha/sha_dma.h"
 | 
			
		||||
 | 
			
		||||
#if SOC_SHA_GDMA
 | 
			
		||||
#include "esp_sha_dma_priv.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* Implementation that should never be optimized out by the compiler */
 | 
			
		||||
static void mbedtls_zeroize( void *v, size_t n )
 | 
			
		||||
{
 | 
			
		||||
@@ -77,10 +73,6 @@ static void mbedtls_zeroize( void *v, size_t n )
 | 
			
		||||
void mbedtls_sha1_init( mbedtls_sha1_context *ctx )
 | 
			
		||||
{
 | 
			
		||||
    memset( ctx, 0, sizeof( mbedtls_sha1_context ) );
 | 
			
		||||
 | 
			
		||||
#if SOC_SHA_GDMA
 | 
			
		||||
    esp_sha_dma_init();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mbedtls_sha1_free( mbedtls_sha1_context *ctx )
 | 
			
		||||
@@ -88,10 +80,6 @@ void mbedtls_sha1_free( mbedtls_sha1_context *ctx )
 | 
			
		||||
    if ( ctx == NULL ) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
#if SOC_SHA_GDMA
 | 
			
		||||
    esp_sha_dma_free();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    mbedtls_zeroize( ctx, sizeof( mbedtls_sha1_context ) );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -48,10 +48,6 @@
 | 
			
		||||
 | 
			
		||||
#include "sha/sha_dma.h"
 | 
			
		||||
 | 
			
		||||
#if SOC_SHA_GDMA
 | 
			
		||||
#include "esp_sha_dma_priv.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* Implementation that should never be optimized out by the compiler */
 | 
			
		||||
static void mbedtls_zeroize( void *v, size_t n )
 | 
			
		||||
{
 | 
			
		||||
@@ -87,10 +83,6 @@ do {                                                    \
 | 
			
		||||
void mbedtls_sha256_init( mbedtls_sha256_context *ctx )
 | 
			
		||||
{
 | 
			
		||||
    memset( ctx, 0, sizeof( mbedtls_sha256_context ) );
 | 
			
		||||
 | 
			
		||||
#if SOC_SHA_GDMA
 | 
			
		||||
    esp_sha_dma_init();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mbedtls_sha256_free( mbedtls_sha256_context *ctx )
 | 
			
		||||
@@ -99,10 +91,6 @@ void mbedtls_sha256_free( mbedtls_sha256_context *ctx )
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#if SOC_SHA_GDMA
 | 
			
		||||
    esp_sha_dma_free();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    mbedtls_zeroize( ctx, sizeof( mbedtls_sha256_context ) );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -54,10 +54,6 @@
 | 
			
		||||
 | 
			
		||||
#include "sha/sha_dma.h"
 | 
			
		||||
 | 
			
		||||
#if SOC_SHA_GDMA
 | 
			
		||||
#include "esp_sha_dma_priv.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* Implementation that should never be optimized out by the compiler */
 | 
			
		||||
static void mbedtls_zeroize( void *v, size_t n )
 | 
			
		||||
{
 | 
			
		||||
@@ -109,10 +105,6 @@ void esp_sha512_set_t( mbedtls_sha512_context *ctx, uint16_t t_val)
 | 
			
		||||
void mbedtls_sha512_init( mbedtls_sha512_context *ctx )
 | 
			
		||||
{
 | 
			
		||||
    memset( ctx, 0, sizeof( mbedtls_sha512_context ) );
 | 
			
		||||
 | 
			
		||||
#if SOC_SHA_GDMA
 | 
			
		||||
    esp_sha_dma_init();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mbedtls_sha512_free( mbedtls_sha512_context *ctx )
 | 
			
		||||
@@ -121,10 +113,6 @@ void mbedtls_sha512_free( mbedtls_sha512_context *ctx )
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#if SOC_SHA_GDMA
 | 
			
		||||
    esp_sha_dma_free();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    mbedtls_zeroize( ctx, sizeof( mbedtls_sha512_context ) );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,130 +11,11 @@
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
#include "esp_sha_dma_priv.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/lock.h>
 | 
			
		||||
 | 
			
		||||
#include "freertos/FreeRTOS.h"
 | 
			
		||||
#include "freertos/task.h"
 | 
			
		||||
 | 
			
		||||
#include "driver/periph_ctrl.h"
 | 
			
		||||
#include "hal/gdma_ll.h"
 | 
			
		||||
#include "soc/soc_caps.h"
 | 
			
		||||
#include "esp_private/gdma.h"
 | 
			
		||||
#include "esp_log.h"
 | 
			
		||||
 | 
			
		||||
#define NEW_CHANNEL_TIMEOUT_MS  1000
 | 
			
		||||
#define NEW_CHANNEL_DELAY_MS    100
 | 
			
		||||
 | 
			
		||||
static const char *TAG = "esp_sha_gdma";
 | 
			
		||||
 | 
			
		||||
static _lock_t gdma_ch_lock;
 | 
			
		||||
/* For GDMA we allocate and reserve a single DMA pair for sha at esp_sha_init
 | 
			
		||||
   and release it esp_sha_free
 | 
			
		||||
   This is done to avoid the GDMA associated overhead when doing multiple sha transforms in a row.
 | 
			
		||||
 | 
			
		||||
    The channel is shared between any sha operations that are running in parallel,
 | 
			
		||||
    access will be limited by the peripheral lock
 | 
			
		||||
 */
 | 
			
		||||
static uint8_t ref_counts;
 | 
			
		||||
 | 
			
		||||
/* The GDMA channel is protected from concurrent access by the general sha peripheral lock */
 | 
			
		||||
static gdma_channel_handle_t tx_channel;
 | 
			
		||||
 | 
			
		||||
/* Allocate a new GDMA channel, will keep trying until NEW_CHANNEL_TIMEOUT_MS */
 | 
			
		||||
static inline esp_err_t esp_sha_gdma_new_channel(gdma_channel_alloc_config_t *channel_config, gdma_channel_handle_t *channel)
 | 
			
		||||
{
 | 
			
		||||
    esp_err_t ret;
 | 
			
		||||
    int time_waited_ms = 0;
 | 
			
		||||
 | 
			
		||||
    while(1) {
 | 
			
		||||
        ret = gdma_new_channel(channel_config, channel);
 | 
			
		||||
 | 
			
		||||
        if (ret == ESP_OK) {
 | 
			
		||||
            break;
 | 
			
		||||
        } else if (time_waited_ms >= 1
 | 
			
		||||
        ) {
 | 
			
		||||
            *channel = NULL;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        time_waited_ms += NEW_CHANNEL_DELAY_MS;
 | 
			
		||||
        vTaskDelay(NEW_CHANNEL_DELAY_MS / portTICK_PERIOD_MS);
 | 
			
		||||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Initialize GDMA module and channels */
 | 
			
		||||
static inline void esp_sha_gdma_init(void)
 | 
			
		||||
{
 | 
			
		||||
    esp_err_t ret;
 | 
			
		||||
 | 
			
		||||
    gdma_channel_alloc_config_t channel_config = {
 | 
			
		||||
        .direction = GDMA_CHANNEL_DIRECTION_TX,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    ret = esp_sha_gdma_new_channel(&channel_config, &tx_channel);
 | 
			
		||||
    if (ret != ESP_OK) {
 | 
			
		||||
 | 
			
		||||
        /* mbedtls_sha_init do not have a way of signaling errors to the caller
 | 
			
		||||
        so we set the channel to NULL and detect it in esp_sha_dma_start */
 | 
			
		||||
        ESP_LOGE(TAG, "Failed to acquire DMA channel, Err=0x%X", ret);
 | 
			
		||||
        tx_channel = NULL;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    gdma_connect(tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SHA, 0));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void esp_sha_dma_init()
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    _lock_acquire(&gdma_ch_lock);
 | 
			
		||||
    if (ref_counts == 0) {
 | 
			
		||||
        esp_sha_gdma_init();
 | 
			
		||||
    }
 | 
			
		||||
    ref_counts++;
 | 
			
		||||
    _lock_release(&gdma_ch_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void esp_sha_gdma_free(void)
 | 
			
		||||
{
 | 
			
		||||
    gdma_disconnect(tx_channel);
 | 
			
		||||
    gdma_del_channel(tx_channel);
 | 
			
		||||
    tx_channel = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void esp_sha_dma_free()
 | 
			
		||||
{
 | 
			
		||||
    _lock_acquire(&gdma_ch_lock);
 | 
			
		||||
    ref_counts--;
 | 
			
		||||
    if (ref_counts == 0) {
 | 
			
		||||
        esp_sha_gdma_free();
 | 
			
		||||
    }
 | 
			
		||||
    _lock_release(&gdma_ch_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#include "esp_crypto_shared_gdma.h"
 | 
			
		||||
 | 
			
		||||
esp_err_t esp_sha_dma_start(const lldesc_t *input)
 | 
			
		||||
{
 | 
			
		||||
#if SOC_GDMA_SUPPORT_EXTMEM
 | 
			
		||||
    int tx_ch_id = 0;
 | 
			
		||||
#endif //SOC_GDMA_SUPPORT_EXTMEM
 | 
			
		||||
 | 
			
		||||
    if (!tx_channel) {
 | 
			
		||||
        /* Will happen if no channel was acquired before timeout */
 | 
			
		||||
        return ESP_FAIL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#if SOC_GDMA_SUPPORT_EXTMEM
 | 
			
		||||
    gdma_get_channel_id(tx_channel, &tx_ch_id);
 | 
			
		||||
    /* An L2 FIFO bigger than 40 bytes is need when accessing external ram */
 | 
			
		||||
    gdma_ll_tx_extend_fifo_size_to(&GDMA, tx_ch_id, 40);
 | 
			
		||||
    gdma_ll_tx_set_block_size_psram(&GDMA, tx_ch_id, GDMA_OUT_EXT_MEM_BK_SIZE_16B);
 | 
			
		||||
#endif //SOC_GDMA_SUPPORT_EXTMEM
 | 
			
		||||
 | 
			
		||||
    gdma_start(tx_channel, (intptr_t)input);
 | 
			
		||||
 | 
			
		||||
    return ESP_OK;
 | 
			
		||||
    return esp_crypto_shared_gdma_start(input, NULL, GDMA_TRIG_PERIPH_SHA);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -22,27 +22,6 @@
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if SOC_SHA_GDMA
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Initialize the GDMA channel
 | 
			
		||||
 *
 | 
			
		||||
 * @note Allocate and initialize a DMA channel (tx) for the SHA peripheral
 | 
			
		||||
 *       Only one channel will be initialized at any given time. If two or more SHA operations are
 | 
			
		||||
 *       run in parallel the channel will be shared sequentially.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
void esp_sha_dma_init(void);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Free the GDMA channel
 | 
			
		||||
 *
 | 
			
		||||
 * @note The channel will only be freed if there are no other SHA operations currently using it
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
void esp_sha_dma_free(void);
 | 
			
		||||
#endif //SOC_SHA_GDMA
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Start the DMA engine
 | 
			
		||||
 *
 | 
			
		||||
 
 | 
			
		||||
@@ -55,13 +55,11 @@
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if SOC_SHA_GDMA
 | 
			
		||||
#define SHA_LOCK() esp_crypto_sha_lock_acquire()
 | 
			
		||||
#define SHA_RELEASE() esp_crypto_sha_lock_release()
 | 
			
		||||
#define SHA_LOCK() esp_crypto_sha_aes_lock_acquire()
 | 
			
		||||
#define SHA_RELEASE() esp_crypto_sha_aes_lock_release()
 | 
			
		||||
#elif SOC_SHA_CRYPTO_DMA
 | 
			
		||||
#define SHA_LOCK() esp_crypto_dma_lock_acquire()
 | 
			
		||||
#define SHA_RELEASE() esp_crypto_dma_lock_release()
 | 
			
		||||
#else
 | 
			
		||||
#define SHA_LOCK() ()
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
const static char *TAG = "esp-sha";
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user