blob: e6c2e94d069707081aa4c447ab1495fa64e6f343 [file] [log] [blame]
// 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 "sw/device/lib/base/mmio.h"
#include <stddef.h>
#include <stdint.h>
/**
* 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,
/** An invalid argument was provided. */
kDifHmacBadArg,
} 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,
/** An invalid argument was provided. */
kDifHmacFifoBadArg,
/**
* 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,
/** An invalid argument was provided. */
kDifHmacDigestBadArg,
/**
* 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;
/** 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_config_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 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 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 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.
* @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);
/**
* 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.
* @return `kDifHmacBadArg` if `hmac` null, `kDifHmacOk` otherwise.
*/
dif_hmac_result_t dif_hmac_mode_sha256_start(const dif_hmac_t *hmac);
/**
* 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 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 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 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 read the HMAC digest and store store the result in the buffer
* referenced by `digest`.
*
* If HMAC is still processing this will return `kDifHmacErrorDigestProcessing`
*
* `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 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_digest_read(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);
#endif // OPENTITAN_SW_DEVICE_LIB_DIF_DIF_HMAC_H_