|  | // Copyright lowRISC contributors. | 
|  | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | // SPDX-License-Identifier: Apache-2.0 | 
|  |  | 
|  | #ifndef OPENTITAN_SW_DEVICE_LIB_DIF_DIF_HMAC_H_ | 
|  | #define OPENTITAN_SW_DEVICE_LIB_DIF_DIF_HMAC_H_ | 
|  |  | 
|  | /** | 
|  | * @file | 
|  | * @brief <a href="/hw/ip/hmac/doc/">HMAC</a> Device Interface Functions | 
|  | */ | 
|  |  | 
|  | #include <stddef.h> | 
|  | #include <stdint.h> | 
|  | #include "sw/device/lib/base/mmio.h" | 
|  |  | 
|  | #ifdef __cplusplus | 
|  | extern "C" { | 
|  | #endif  // __cplusplus | 
|  |  | 
|  | /** | 
|  | * HMAC interrupt  configuration. | 
|  | * | 
|  | * Enumeration used to enable, disable, test and query the HMAC interrupts. | 
|  | * Please see the comportability specification for more information: | 
|  | * https://docs.opentitan.org/doc/rm/comportability_specification/ | 
|  | */ | 
|  | typedef enum dif_hmac_interrupt { | 
|  | /** | 
|  | * HMAC is done. | 
|  | * | 
|  | * Associated with the `hmac.INTR_STATE.hmac_done` hardware interrupt. | 
|  | */ | 
|  | kDifHmacInterruptHmacDone = 0, | 
|  |  | 
|  | /** | 
|  | * FIFO empty. | 
|  | * | 
|  | * Associated with the `hmac.INTR_STATE.fifo_empty` hardware interrupt. | 
|  | */ | 
|  | kDifHmacInterruptFifoEmpty, | 
|  |  | 
|  | /** | 
|  | * HMAC error occurred. | 
|  | * | 
|  | * Associated with the `hmac.INTR_STATE.hmac_err` hardware interrupt. | 
|  | */ | 
|  | kDifHmacInterruptHmacErr, | 
|  | } dif_hmac_interrupt_t; | 
|  |  | 
|  | /** | 
|  | * Generic enable/disable enumeration. | 
|  | * | 
|  | * Enumeration used to enable/disable bits, flags, ... | 
|  | */ | 
|  | typedef enum dif_hmac_enable { | 
|  | /** Enable interrupt. */ | 
|  | kDifHmacEnable = 0, | 
|  | /** Disable interrupt. */ | 
|  | kDifHmacDisable, | 
|  | } dif_hmac_enable_t; | 
|  |  | 
|  | /** | 
|  | * Supported HMAC modes of operation. | 
|  | */ | 
|  | typedef enum dif_hmac_mode { | 
|  | /** The HMAC mode. */ | 
|  | kDifHmacModeHmac = 0, | 
|  | /** The SHA256-only mode. */ | 
|  | kDifHmacModeSha256, | 
|  | } dif_hmac_mode_t; | 
|  |  | 
|  | /** | 
|  | * Supported byte endienness options. | 
|  | */ | 
|  | typedef enum dif_hmac_endianness { | 
|  | /** Big endian byte ordering. */ | 
|  | kDifHmacEndiannessBig = 0, | 
|  | /** Little endian byte ordering. */ | 
|  | kDifHmacEndiannessLittle, | 
|  | } dif_hmac_endianness_t; | 
|  |  | 
|  | /** | 
|  | * Error codes for HMAC functions that may exhibit generic failures. | 
|  | */ | 
|  | typedef enum dif_hmac_result { | 
|  | /** No error occurred. */ | 
|  | kDifHmacOk = 0, | 
|  | /** An unknown error occurred. */ | 
|  | kDifHmacError = 1, | 
|  | /** An invalid argument was provided. */ | 
|  | kDifHmacBadArg = 2, | 
|  | } dif_hmac_result_t; | 
|  |  | 
|  | /** | 
|  | * Error codes for HMAC FIFO operations that may fail. | 
|  | */ | 
|  | typedef enum dif_hmac_fifo_result { | 
|  | /** No error occurred. */ | 
|  | kDifHmacFifoOk = 0, | 
|  | /** An unknown error occurred. */ | 
|  | kDifHmacFifoError = kDifHmacError, | 
|  | /** An invalid argument was provided. */ | 
|  | kDifHmacFifoBadArg = kDifHmacBadArg, | 
|  | /** | 
|  | * The FIFO filled up before the buffer was fully consumed. | 
|  | * | 
|  | * Retryable. This error indicates that FIFO has filled up and will empty over | 
|  | * time. A function that returns this error may be retried at any time, or the | 
|  | * caller may choose to do so when the `kDifHmacInterruptFifoEmpty` interrupt | 
|  | * is raised, provided this interrupt has been enabled via the interrupt API. | 
|  | */ | 
|  | kDifHmacFifoFull, | 
|  | } dif_hmac_fifo_result_t; | 
|  |  | 
|  | /** | 
|  | * Error codes for reading the HMAC digest. | 
|  | */ | 
|  | typedef enum dif_hmac_digest_result { | 
|  | /** No error occurred. */ | 
|  | kDifHmacDigestOk = 0, | 
|  | /** An unknown error occurred. */ | 
|  | kDifHmacDigestError = kDifHmacError, | 
|  | /** An invalid argument was provided. */ | 
|  | kDifHmacDigestBadArg = kDifHmacBadArg, | 
|  | /** | 
|  | * The HMAC operation is still in progress. | 
|  | * | 
|  | * Retryable. This error indicates HMAC is still processing and will finish in | 
|  | * time. A function that returns this error may be retried at any time, or the | 
|  | *  caller may choose to do so when the `kDifHmacInterruptHmacDone` interrupt | 
|  | *  is raised, provided this interrupt has been enabled via the interrupt API. | 
|  | * | 
|  | *  Any function that returns this error is guaranteed to have not produced | 
|  | *  any side effects. | 
|  | */ | 
|  | kDifHmacDigestProcessing, | 
|  | } dif_hmac_digest_result_t; | 
|  |  | 
|  | /** | 
|  | * Configuration for initializing the HMAC device. | 
|  | */ | 
|  | typedef struct dif_hmac_config { | 
|  | /** The base address for registers in the HMAC IP. */ | 
|  | mmio_region_t base_addr; | 
|  | } dif_hmac_config_t; | 
|  |  | 
|  | /** | 
|  | * Configuration for a single HMAC Transaction | 
|  | */ | 
|  | typedef struct dif_hmac_transaction { | 
|  | /** Byte endianness for writes to the FIFO. */ | 
|  | dif_hmac_endianness_t message_endianness; | 
|  | /** Byte endianness for reads from the digest. */ | 
|  | dif_hmac_endianness_t digest_endianness; | 
|  | } dif_hmac_transaction_t; | 
|  |  | 
|  | /** | 
|  | * A typed representation of the HMAC digest. | 
|  | */ | 
|  | typedef struct dif_hmac_digest { uint32_t digest[8]; } dif_hmac_digest_t; | 
|  |  | 
|  | /** | 
|  | * State for a particular HMAC device. | 
|  | * | 
|  | * Its member variables should be considered private, and are only provided so | 
|  | * that callers can allocate it. | 
|  | */ | 
|  | typedef struct dif_hmac { mmio_region_t base_addr; } dif_hmac_t; | 
|  |  | 
|  | /** | 
|  | * Initializes the HMAC device described by `config`, writing internal state to | 
|  | * `hmac_out`. | 
|  | * | 
|  | * This function *must* be called on a particular `mmio_region_t` before calling | 
|  | * any other functions in this header with that `mmio_region_t`. | 
|  | * | 
|  | * @param config Configuration supplied for initializing a particular device. | 
|  | * @param[out] hmac_out The location at which to write HMAC state. This location | 
|  | *                 must be valid to write to. | 
|  | * @return `kDifHmacBadArg` if `config` is null or contains illegal | 
|  | *          arguments or `hmac_out` is null, `kDifHmacOk` otherwise. | 
|  | */ | 
|  | dif_hmac_result_t dif_hmac_init(const dif_hmac_config_t *config, | 
|  | dif_hmac_t *hmac_out); | 
|  |  | 
|  | /** | 
|  | * HMAC get requested IRQ state. | 
|  | * | 
|  | * Get the state of the requested IRQ in `irq_type`. | 
|  | * | 
|  | * @param hmac HMAC state data. | 
|  | * @param irq_type IRQ to get the state of. | 
|  | * @param[out] state IRQ state passed back to the caller. | 
|  | * @return `dif_hmac_result_t`. | 
|  | */ | 
|  | dif_hmac_result_t dif_hmac_irq_state_get(const dif_hmac_t *hmac, | 
|  | dif_hmac_interrupt_t irq_type, | 
|  | dif_hmac_enable_t *state); | 
|  | /** | 
|  | * HMAC clear requested IRQ state. | 
|  | * | 
|  | * Clear the state of the requested IRQ in `irq_type`. Primary use of this | 
|  | * function is to de-assert the interrupt after it has been serviced. | 
|  | * | 
|  | * @param hmac HMAC state data. | 
|  | * @param irq_type IRQ to be de-asserted. | 
|  | * @return `dif_hmac_result_t`. | 
|  | */ | 
|  | dif_hmac_result_t dif_hmac_irq_state_clear(const dif_hmac_t *hmac, | 
|  | dif_hmac_interrupt_t irq_type); | 
|  |  | 
|  | /** | 
|  | * HMAC disable interrupts. | 
|  | * | 
|  | * Disable generation of all HMAC interrupts, and pass previous interrupt state | 
|  | * in `state` back to the caller. Parameter `state` is ignored if NULL. | 
|  | * | 
|  | * @param hmac HMAC state data. | 
|  | * @param[out] state IRQ state passed back to the caller. | 
|  | * @return 'dif_hmac_result_t'. | 
|  | */ | 
|  | dif_hmac_result_t dif_hmac_irqs_disable(const dif_hmac_t *hmac, | 
|  | uint32_t *state); | 
|  |  | 
|  | /** | 
|  | * HMAC restore IRQ state. | 
|  | * | 
|  | * Restore previous HMAC IRQ state. This function is used to restore the | 
|  | * HMAC interrupt state prior to `dif_hmac_irqs_disable` function call. | 
|  | * | 
|  | * @param hmac HMAC state data. | 
|  | * @param state IRQ state to restore. | 
|  | * @return 'dif_hmac_result_t'. | 
|  | */ | 
|  | dif_hmac_result_t dif_hmac_irqs_restore(const dif_hmac_t *hmac, uint32_t state); | 
|  |  | 
|  | /** | 
|  | * HMAC interrupt control. | 
|  | * | 
|  | * Enable/disable an HMAC interrupt specified in `irq_type`. | 
|  | * | 
|  | * @param hmac HMAC state data. | 
|  | * @param irq_type HMAC interrupt type. | 
|  | * @param enable enable or disable the interrupt. | 
|  | * @return `dif_hmac_result_t`. | 
|  | */ | 
|  | dif_hmac_result_t dif_hmac_irq_control(const dif_hmac_t *hmac, | 
|  | dif_hmac_interrupt_t irq_type, | 
|  | dif_hmac_enable_t enable); | 
|  |  | 
|  | /** | 
|  | * HMAC interrupt force. | 
|  | * | 
|  | * Force interrupt specified in `irq_type`. | 
|  | * | 
|  | * @param hmac HMAC state data. | 
|  | * @param irq_type HMAC interrupt type to be forced. | 
|  | * @return `dif_hmac_result_t`. | 
|  | */ | 
|  | dif_hmac_result_t dif_hmac_irq_force(const dif_hmac_t *hmac, | 
|  | dif_hmac_interrupt_t irq_type); | 
|  |  | 
|  | /** | 
|  | * Resets the HMAC engine and readies it to receive a new message to process an | 
|  | * HMAC digest. | 
|  | * | 
|  | * This function causes the HMAC engine to start its operation. After a | 
|  | * successful call to this function, |dif_hmac_fifo_push()| can be called to | 
|  | * write the message for HMAC processing. | 
|  | * | 
|  | * This function must be called with a valid `key` that references a 32-byte, | 
|  | * contiguous, readable region where the key may be copied from. | 
|  | * | 
|  | * @param hmac The HMAC device to start HMAC operation for. | 
|  | * @param key The 256-bit HMAC key. | 
|  | * @param config The per-transaction configuration. | 
|  | * @return `kDifHmacBadArg` if `hmac` or `key` is null, `kDifHmacOk` otherwise. | 
|  | */ | 
|  | dif_hmac_result_t dif_hmac_mode_hmac_start(const dif_hmac_t *hmac, | 
|  | const uint8_t *key, | 
|  | const dif_hmac_transaction_t config); | 
|  |  | 
|  | /** | 
|  | * Resets the HMAC engine and readies it to receive a new message to process a | 
|  | * SHA256 digest. | 
|  | * | 
|  | * This function causes the HMAC engine to start its operation. After a | 
|  | * successful call to this function, |dif_hmac_fifo_push()| can be called to | 
|  | * write the message for SHA256 processing. | 
|  | * | 
|  | * @param hmac The HMAC device to start SHA256 operation for. | 
|  | * @param config The per-transaction configuration. | 
|  | * @return `kDifHmacBadArg` if `hmac` null, `kDifHmacOk` otherwise. | 
|  | */ | 
|  | dif_hmac_result_t dif_hmac_mode_sha256_start( | 
|  | const dif_hmac_t *hmac, const dif_hmac_transaction_t config); | 
|  |  | 
|  | /** | 
|  | * Attempts to send `len` bytes from the buffer pointed to by `data` to the | 
|  | * device described by `hmac`. This function will send to the message FIFO until | 
|  | * the FIFO fills up or `len` bytes have been sent. | 
|  | * | 
|  | * In the event that the FIFO fills up before `len` bytes have been sent this | 
|  | * function will return a `kDifHmacFifoFull` error. In this case it is valid | 
|  | * to call this function again by advancing `data` by `len` - |*bytes_sent| | 
|  | * bytes. It may be desirable to wait for space to free up on the FIFO before | 
|  | * issuing subsequent calls to this function, but it is not strictly | 
|  | * necessary. The number of entries in the FIFO can be queried with | 
|  | * `dif_hmac_fifo_count_entries()`. | 
|  | * | 
|  | * `data` *must* point to an allocated buffer of at least length `len`. | 
|  | * | 
|  | * @param hmac The HMAC device to send to. | 
|  | * @param data A contiguous buffer to copy from. | 
|  | * @param len The length of the buffer to copy from. | 
|  | * @param[out] bytes_sent The number of bytes sent to the FIFO (optional). | 
|  | * @return `kDifHmacFifoFull` if the FIFO fills up, `kDifHmacFifoBadArg` if | 
|  | *         `hmac` or `data` is null, and `kDifHmacFifoOk` otherwise. | 
|  | */ | 
|  | dif_hmac_fifo_result_t dif_hmac_fifo_push(const dif_hmac_t *hmac, | 
|  | const void *data, size_t len, | 
|  | size_t *bytes_sent); | 
|  |  | 
|  | /** | 
|  | * Retrieves the number of entries in the HMAC FIFO. These entries may be | 
|  | * semi-arbitrary in length; this function should not be used to calculate | 
|  | * message length. | 
|  | * | 
|  | * @param hmac The HMAC device to get the FIFO depth for. | 
|  | * @param[out] num_entries The number of entries in the FIFO. | 
|  | * @return `kDifHmacBadArg` if `hmac` or `num_entries` is null, `kDifHmacOk` | 
|  | *         otherwise. | 
|  | */ | 
|  | dif_hmac_result_t dif_hmac_fifo_count_entries(const dif_hmac_t *hmac, | 
|  | uint32_t *num_entries); | 
|  |  | 
|  | /** | 
|  | * Retrieves the number of bits in the loaded HMAC device. | 
|  | * `dif_hmac_fifo_count_entries()` should be called before this function to | 
|  | * ensure the FIFO is empty, as any bits in the FIFO are not counted in | 
|  | * `msg_len`. | 
|  | * | 
|  | * @param hmac The HMAC device to get the message length for. | 
|  | * @param[out] msg_len The number of bits in the HMAC message. | 
|  | * @return `kDifHmacBadArg` if `hmac` or `msg_len` is null, `kDifHmacOk` | 
|  | *         otherwise. | 
|  | */ | 
|  | dif_hmac_result_t dif_hmac_get_message_length(const dif_hmac_t *hmac, | 
|  | uint64_t *msg_len); | 
|  |  | 
|  | /** | 
|  | * Attempts to run HMAC or SHA256 depending on the mode `hmac` was initialized | 
|  | * in. Calls to this function always succeed and return without blocking. The | 
|  | * caller can use `dif_hmac_check_state()` to check for errors and for the | 
|  | * `DIF_HMAC_DONE` status before reading the digest with | 
|  | * `dif_hmac_digest_read()`. | 
|  | * | 
|  | * @param hmac The HMAC device to initiate the run on. | 
|  | * @return `kDifHmacBadArg` if `hmac` is null `kDifHmacOk` otherwise. | 
|  | */ | 
|  | dif_hmac_result_t dif_hmac_process(const dif_hmac_t *hmac); | 
|  |  | 
|  | /** | 
|  | * Attempts to finish a transaction started with `dif_hmac_mode_*_start`, and | 
|  | * reads the final digest in the buffer referenced by `digest`. | 
|  | * | 
|  | * This queries the `INTR_STATE` register to check if the HMAC is finished, and | 
|  | * will acknowledge a `hmac_done` interrupt. If that register is not pending, | 
|  | * then this function assumes HMAC is still processing and will return | 
|  | * `kDifHmacErrorDigestProcessing`. | 
|  | * | 
|  | * Once the digest has been read, the HMAC and SHA256 datapaths are disabled, | 
|  | * clearing the digest registers. | 
|  | * | 
|  | * `digest` must reference an allocated, contiguous, 32-byte buffer. This buffer | 
|  | * shall also be 4-byte aligned. This is all consistent with the platform | 
|  | * requirements for size and alignment requirements of `dif_hmac_digest_t`. | 
|  | * | 
|  | * @param hmac The HMAC device to read the digest from. | 
|  | * @param[out] digest A contiguous 32-byte, 4-byte aligned buffer for the | 
|  | * digest. | 
|  | * @return `kDifHmacBadArg` if `hmac` or `digest` is null, | 
|  | *         `kDifHmacDigestProcessing` if HMAC is still processing, and | 
|  | *         `kDifHmacOk` otherwise. | 
|  | */ | 
|  | dif_hmac_digest_result_t dif_hmac_finish(const dif_hmac_t *hmac, | 
|  | dif_hmac_digest_t *digest); | 
|  |  | 
|  | /** | 
|  | * Randomizes internal secret registers on the HMAC device. This includes the | 
|  | * key, hash value, and internal state machine. The value of `entropy` will be | 
|  | * used to "randomize" the internal state of the HMAC device. See the HMAC IP | 
|  | * documentation for more information: hw/ip/hmac/doc. | 
|  | * | 
|  | * @param hmac The HMAC device to clobber state on. | 
|  | * @param entropy A source of randomness to write to the HMAC internal state. | 
|  | * @return `kDifHmacBadArg` if `hmac` is null `kDifHmacOk` otherwise. | 
|  | */ | 
|  | dif_hmac_result_t dif_hmac_wipe_secret(const dif_hmac_t *hmac, | 
|  | uint32_t entropy); | 
|  |  | 
|  | #ifdef __cplusplus | 
|  | }  // extern "C" | 
|  | #endif  // __cplusplus | 
|  |  | 
|  | #endif  // OPENTITAN_SW_DEVICE_LIB_DIF_DIF_HMAC_H_ |