/* * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once #include #include "hal/sha_types.h" #include "soc/dport_reg.h" #include "soc/hwcrypto_reg.h" #include "soc/dport_access.h" #include "hal/misc.h" #ifdef __cplusplus extern "C" { #endif #define SHA_LL_TYPE_OFFSET 0x10 /** * @brief Enable the bus clock for SHA peripheral module * * @param enable true to enable the module, false to disable the module */ static inline void sha_ll_enable_bus_clock(bool enable) { if (enable) { DPORT_SET_PERI_REG_MASK(DPORT_PERI_CLK_EN_REG, DPORT_PERI_EN_SHA); } else { DPORT_CLEAR_PERI_REG_MASK(DPORT_PERI_CLK_EN_REG, DPORT_PERI_EN_SHA); } } /// use a macro to wrap the function, force the caller to use it in a critical section /// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance #define sha_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; sha_ll_enable_bus_clock(__VA_ARGS__) /** * @brief Reset the SHA peripheral module */ static inline void sha_ll_reset_register(void) { DPORT_SET_PERI_REG_MASK(DPORT_PERI_RST_EN_REG, DPORT_PERI_EN_SHA); DPORT_CLEAR_PERI_REG_MASK(DPORT_PERI_RST_EN_REG, DPORT_PERI_EN_SHA); // Clear reset on secure boot also, otherwise SHA is held in reset DPORT_CLEAR_PERI_REG_MASK(DPORT_PERI_RST_EN_REG, DPORT_PERI_EN_SECUREBOOT); } /// use a macro to wrap the function, force the caller to use it in a critical section /// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance #define sha_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; sha_ll_reset_register(__VA_ARGS__) /** * @brief Returns the LOAD_REG register address for the given sha type * * @param sha_type The SHA algorithm type * @return uint32_t the LOAD_REG register address */ inline static uint32_t SHA_LOAD_REG(esp_sha_type sha_type) { return SHA_1_LOAD_REG + sha_type * SHA_LL_TYPE_OFFSET; } /** * @brief Returns the BUSY register address for the given sha type * * @param sha_type The SHA algorithm type * @return uint32_t the BUSY register address */ inline static uint32_t SHA_BUSY_REG(esp_sha_type sha_type) { return SHA_1_BUSY_REG + sha_type * SHA_LL_TYPE_OFFSET; } /** * @brief Returns the START register address for the given sha type * * @param sha_type The SHA algorithm type * @return uint32_t the START register address */ inline static uint32_t SHA_START_REG(esp_sha_type sha_type) { return SHA_1_START_REG + sha_type * SHA_LL_TYPE_OFFSET; } /** * @brief Returns the CONTINUE register address for the given sha type * * @param sha_type The SHA algorithm type * @return uint32_t the CONTINUE register address */ inline static uint32_t SHA_CONTINUE_REG(esp_sha_type sha_type) { return SHA_1_CONTINUE_REG + sha_type * SHA_LL_TYPE_OFFSET; } /** * @brief Start a new SHA block conversion (no initial hash in HW) * * @param sha_type The SHA algorithm type */ static inline void sha_ll_start_block(esp_sha_type sha_type) { DPORT_REG_WRITE(SHA_START_REG(sha_type), 1); } /** * @brief Continue a SHA block conversion (initial hash in HW) * * @param sha_type The SHA algorithm type */ static inline void sha_ll_continue_block(esp_sha_type sha_type) { DPORT_REG_WRITE(SHA_CONTINUE_REG(sha_type), 1); } /** * @brief Load the current hash digest to digest register * * @param sha_type The SHA algorithm type */ static inline void sha_ll_load(esp_sha_type sha_type) { DPORT_REG_WRITE(SHA_LOAD_REG(sha_type), 1); } /** * @brief Checks if the SHA engine is currently busy hashing a block * * @return true SHA engine busy * @return false SHA engine idle */ static inline bool sha_ll_busy(void) { return (DPORT_REG_READ(SHA_1_BUSY_REG) || DPORT_REG_READ(SHA_256_BUSY_REG) || DPORT_REG_READ(SHA_384_BUSY_REG) || DPORT_REG_READ(SHA_512_BUSY_REG)); } /** * @brief Write a text (message) block to the SHA engine * * @param input_text Input buffer to be written to the SHA engine * @param block_word_len Number of words in block */ static inline void sha_ll_fill_text_block(const void *input_text, size_t block_word_len) { uint32_t *reg_addr_buf = NULL; uint32_t *data_words = NULL; reg_addr_buf = (uint32_t *)(SHA_TEXT_BASE); data_words = (uint32_t *)input_text; for (size_t i = 0; i < block_word_len; i++) { reg_addr_buf[i] = HAL_SWAP32(data_words[i]); } } /** * @brief Read the message digest from the SHA engine * * @param sha_type The SHA algorithm type * @param digest_state Buffer that message digest will be written to * @param digest_word_len Length of the message digest */ static inline void sha_ll_read_digest(esp_sha_type sha_type, void *digest_state, size_t digest_word_len) { uint32_t *digest_state_words = (uint32_t *)digest_state; uint32_t *reg_addr_buf = (uint32_t *)(SHA_TEXT_BASE); if (sha_type == SHA2_384 || sha_type == SHA2_512) { /* for these ciphers using 64-bit states, swap each pair of words */ DPORT_INTERRUPT_DISABLE(); // Disable interrupt only on current CPU. for (size_t i = 0; i < digest_word_len; i += 2) { digest_state_words[i + 1] = DPORT_SEQUENCE_REG_READ((uint32_t)®_addr_buf[i]); digest_state_words[i] = DPORT_SEQUENCE_REG_READ((uint32_t)®_addr_buf[i + 1]); } DPORT_INTERRUPT_RESTORE(); // restore the previous interrupt level } else { esp_dport_access_read_buffer(digest_state_words, (uint32_t)®_addr_buf[0], digest_word_len); } } #ifdef __cplusplus } #endif