| /* |
| * Copyright (c) 2024 Raspberry Pi (Trading) Ltd. |
| * |
| * SPDX-License-Identifier: BSD-3-Clause |
| */ |
| |
| #ifndef _HARDWARE_SHA256_H |
| #define _HARDWARE_SHA256_H |
| |
| #include "pico.h" |
| #include "hardware/structs/sha256.h" |
| |
| /** \file hardware/sha256.h |
| * \defgroup hardware_sha256 hardware_sha256 |
| * |
| * \brief Hardware SHA-256 Accelerator API |
| * |
| * RP2350 is equipped with an implementation of the SHA-256 hash algorithm. |
| * The hardware should first be configured by calling the \ref sha256_set_dma_size and \ref sha256_set_bswap functions. |
| * To generate a new hash the hardware should first be initialised by calling \ref sha256_start. |
| * The hardware is ready to accept data when \ref sha256_is_ready returns true, |
| * at which point the data to be hashed can be written to the address returned by \ref sha256_get_write_addr. |
| * The hardware requires 64 bytes to be written in one go or else \ref sha256_err_not_ready will indicate an error and |
| * the hashing process must be restarted. |
| * \ref sha256_is_sum_valid will return true when there is a valid checksum result which can be retrieved by calling \ref sha256_get_result. |
| */ |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| // PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_HARDWARE_SHA256, Enable/disable hardware_sha256 assertions, type=bool, default=0, group=hardware_sha256 |
| #ifndef PARAM_ASSERTIONS_ENABLED_HARDWARE_SHA256 |
| #ifdef PARAM_ASSERTIONS_ENABLED_SHA256 // backwards compatibility with SDK < 2.0.0 |
| #define PARAM_ASSERTIONS_ENABLED_HARDWARE_SHA256 PARAM_ASSERTIONS_ENABLED_SHA256 |
| #else |
| #define PARAM_ASSERTIONS_ENABLED_HARDWARE_SHA256 0 |
| #endif |
| #endif |
| |
| /*! \brief Size of a sha256 result in bytes. |
| * \ingroup hardware_sha256 |
| */ |
| #define SHA256_RESULT_BYTES 32 |
| |
| /*! \brief SHA-256 endianness definition used in the API |
| * \ingroup hardware_sha256 |
| */ |
| enum sha256_endianness { |
| SHA256_LITTLE_ENDIAN, ///< Little Endian |
| SHA256_BIG_ENDIAN, ///< Big Endian |
| }; |
| |
| /*! \brief SHA-256 result generated by the API |
| * \ingroup hardware_sha256 |
| */ |
| typedef union { |
| uint32_t words[SHA256_RESULT_BYTES/4]; |
| uint8_t bytes[SHA256_RESULT_BYTES]; |
| } sha256_result_t; |
| |
| /*! \brief Configure the correct DMA data size. |
| * \ingroup hardware_sha256 |
| * |
| * This must be configured before the DMA channel is triggered and ensures the correct number of transfers is requested per block. |
| * |
| * \param size_in_bytes Size of DMA transfers, either 1, 2 or 4 bytes only. |
| */ |
| static inline void sha256_set_dma_size(uint size_in_bytes) { |
| uint32_t val; |
| invalid_params_if(HARDWARE_SHA256, size_in_bytes != 1 && size_in_bytes != 2 && size_in_bytes != 4); |
| if (size_in_bytes == 1) { |
| val = SHA256_CSR_DMA_SIZE_VALUE_8BIT; |
| } else if (size_in_bytes == 2) { |
| val = SHA256_CSR_DMA_SIZE_VALUE_16BIT; |
| } else { |
| val = SHA256_CSR_DMA_SIZE_VALUE_32BIT; |
| } |
| hw_write_masked(&sha256_hw->csr, val << SHA256_CSR_DMA_SIZE_LSB, SHA256_CSR_DMA_SIZE_BITS); |
| } |
| |
| |
| /*! \brief Enable or disable byte swapping of 32-bit values. |
| * \ingroup hardware_sha256 |
| * |
| * The SHA256 algorithm expects bytes in big endian order, but the system bus deals with little endian data, |
| * so control is provided to convert little endian bus data to big endian internal data. This defaults to true |
| * |
| * \param swap false to disable byte swapping |
| */ |
| static inline void sha256_set_bswap(bool swap) { |
| if (swap) { |
| hw_set_bits(&sha256_hw->csr, SHA256_CSR_BSWAP_BITS); |
| } else { |
| hw_clear_bits(&sha256_hw->csr, SHA256_CSR_BSWAP_BITS); |
| } |
| } |
| |
| /*! \brief Prepare the hardware for a new checksum. |
| * \ingroup hardware_sha256 |
| * |
| * Called to initialise the hardware before starting the checksum calculation |
| */ |
| static inline void sha256_start(void) { |
| hw_set_bits(&sha256_hw->csr, SHA256_CSR_START_BITS); |
| } |
| |
| /*! \brief Check if a valid checksum has been calculated |
| * \ingroup hardware_sha256 |
| * |
| * The checksum result will be invalid when data is first written to the hardware, |
| * and then once 64 bytes of data has been written it may take some time to complete the digest of the current block. |
| * This function can be used to determine when the checksum is valid. |
| * |
| * \return True if \ref sha256_get_result would return a valid result |
| */ |
| static inline bool sha256_is_sum_valid(void) { |
| return sha256_hw->csr & SHA256_CSR_SUM_VLD_BITS; |
| } |
| |
| /*! \brief Check if a the hardware is ready to accept more data |
| * \ingroup hardware_sha256 |
| * |
| * After writing 64 bytes of data to the hardware, it will be unable to accept more data for a time. |
| * Call this to check if the hardware is ready for more data to be written. \see sha256_err_not_ready |
| * |
| * \return True if the hardware is ready to receive more data |
| */ |
| static inline bool sha256_is_ready(void) { |
| return sha256_hw->csr & SHA256_CSR_WDATA_RDY_BITS; |
| } |
| |
| /*! \brief Wait until the checksum is valid |
| * \ingroup hardware_sha256 |
| * |
| * When a multiple of 64 bytes of data has been written to the hardware, |
| * the checksum will be valid once the digest of the current block is complete. |
| * This function waits until when the checksum result is valid. |
| */ |
| static inline void sha256_wait_valid_blocking(void) { |
| while (!sha256_is_sum_valid()) { |
| tight_loop_contents(); |
| } |
| } |
| |
| /*! \brief Wait until the hardware is ready to accept more data |
| * \ingroup hardware_sha256 |
| * |
| * Before writing to the hardware, it's necessary to check it is ready to accept more data. |
| * This function waits until the hardware is ready to accept more data |
| */ |
| static inline void sha256_wait_ready_blocking(void) { |
| while (!sha256_is_ready()) { |
| tight_loop_contents(); |
| } |
| } |
| |
| /*! \brief Get the checksum result |
| * \ingroup hardware_sha256 |
| * |
| * Read the 32 byte result calculated by the hardware. Only valid if \ref sha256_is_sum_valid is True |
| * |
| * \param out The checksum result |
| */ |
| void sha256_get_result(sha256_result_t *out, enum sha256_endianness endianness); |
| |
| /*! \brief Check if data was written before the hardware was ready |
| * \ingroup hardware_sha256 |
| * |
| * Indicates if an error has occurred due to data being written when the hardware is not ready. |
| * |
| * \return True if data was written before the hardware was ready |
| */ |
| static inline bool sha256_err_not_ready(void) { |
| return sha256_hw->csr & SHA256_CSR_ERR_WDATA_NOT_RDY_BITS; |
| } |
| |
| /*! \brief Clear the "not ready" error condition |
| * \ingroup hardware_sha256 |
| * |
| * Resets the hardware if a "not ready" error condition is indicated. |
| */ |
| static inline void sha256_err_not_ready_clear(void) { |
| hw_clear_bits(&sha256_hw->csr, SHA256_CSR_ERR_WDATA_NOT_RDY_BITS); |
| } |
| |
| /*! \brief Address to write the data to be hashed |
| * \ingroup hardware_sha256 |
| * |
| * Returns the hardware address where data to be hashed should be written |
| * |
| * \return Address to write data to be hashed |
| */ |
| static inline volatile void *sha256_get_write_addr(void) { |
| return &sha256_hw->wdata; |
| } |
| |
| /*! \brief Write one 32bit word of data to the SHA-256 hardware |
| * \ingroup hardware_sha256 |
| * |
| * \param word data to write |
| */ |
| static inline void sha256_put_word(uint32_t word) { |
| sha256_hw->wdata = word; |
| } |
| |
| /*! \brief Write one byte of data to the SHA-256 hardware |
| * \ingroup hardware_sha256 |
| * |
| * \param b data to write |
| */ |
| static inline void sha256_put_byte(uint8_t b) { |
| *((io_rw_8*)&sha256_hw->wdata) = b; |
| } |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif |