blob: db8fca6ffc6026d5d80effc75593c61860de25b6 [file] [log] [blame]
/*
* 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