text: // 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_ENTROPY_H_
  #define OPENTITAN_SW_DEVICE_LIB_DIF_DIF_ENTROPY_H_
  
  /**
   * @file
   * @brief <a href="/hw/ip/entropy_src/doc/">Entropy Source</a> Device Interface
   * Functions
   */
  
  #include <stdint.h>
  
  #include "sw/device/lib/base/mmio.h"
  #include "sw/device/lib/dif/dif_warn_unused_result.h"
  
  #ifdef __cplusplus
  extern "C" {
  #endif  // __cplusplus
  
  enum {
    /**
     * Maximum pre-conditioning FIFO capacity.
     */
    // TODO: Synchronize value with hardware.
    kDifEntropyFifoMaxCapacity = 64,
  };
  
  /**
   * A toggle state: enabled, or disabled.
   *
   * This enum may be used instead of a `bool` when describing an enabled/disabled
   * state.
   */
  typedef enum dif_entropy_toggle {
    /*
     * The "enabled" state.
     */
    kDifEntropyToggleEnabled,
    /**
     * The "disabled" state.
     */
    kDifEntropyToggleDisabled,
  } dif_entropy_toggle_t;
  
  /**
   * A statistical test on the bits emitted by an entropy source.
   */
  typedef enum dif_entropy_test {
    /**
     * An SP 800-90B repetition count test.
     *
     * This test screens for stuck bits, or a total failure of the noise source.
     * This test fails if any sequence of bits repeats too many times in a row
     * for too many samples.
     */
    kDifEntropyTestRepCount,
  
    /**
     * An SP 800-90B adaptive proportion test.
     *
     * This test screens for statistical bias in the number of ones or zeros
     * output by the noise source.
     */
    kDifEntropyTestAdaptiveProportion,
  
    /**
     * A bucket test.
     *
     * This test looks for correlations between individual noise channels.
     */
    kDifEntropyTestBucket,
  
    /**
     * A "Markov" test.
     *
     * This test looks for unexpected first-order temporal correlations
     * between individual noise channels.
     */
    kDifEntropyTestMarkov,
  
    /**
     * A firmware-driven "mailbox" test.
     *
     * This test allows firmware to inspect 2kbit blocks of entropy, and signal
     * potential concerns to the hardware.
     */
    kDifEntropyTestMailbox,
  
    /**
     * A vendor-specific test implemented externally to the IP.
     */
    kDifEntropyTestVendorSpecific,
  
    /** \internal */
    kDifEntropyTestNumVariants,
  } dif_entropy_test_t;
  
  /**
   * A mode of operation for the entropy source.
   */
  typedef enum dif_entropy_mode {
    /**
     * Indicates that the source is disabled.
     */
    kDifEntropyModeDisabled = 0,
  
    /**
     * The physical true random number generator mode.
     *
     * This mode uses a physical random noise generator for operation, and is
     * truly random. This noise generator is compatible with SP 800-90B.
     */
    kDifEntropyModePtrng = 1,
  
    /**
     * The Linear Feedback Shift Register (LFSR) mode.
     *
     * This mode is digital, and as such is only pseudo-random and intended
     * for test purposes only.
     *
     * In this mode, the `dif_entropy_config.lfsr_seed` value is used to
     * initialize the internal state of the LFSR.
     */
    kDifEntropyModeLfsr = 2,
  } dif_entropy_mode_t;
  
  /**
   * A single-bit RNG mode, where only one bit is sampled.
   */
  typedef enum dif_entropy_single_bit_mode {
    /**
     * Single-bit-mode, sampling the zeroth bit.
     */
    kDifEntropySingleBitMode0 = 0,
    /**
     * Single-bit-mode, sampling the first bit.
     */
    kDifEntropySingleBitMode1 = 1,
    /**
     * Single-bit-mode, sampling the second bit.
     */
    kDifEntropySingleBitMode2 = 2,
    /**
     * Single-bit-mode, sampling the third bit.
     */
    kDifEntropySingleBitMode3 = 3,
    /**
     * Indicates that single-bit-mode is disabled.
     */
    kDifEntropySingleBitModeDisabled = 4,
  } dif_entropy_single_bit_mode_t;
  
  /**
   * Criteria used by various entropy source health tests to decide whether the
   * test has failed.
   */
  typedef struct dif_entropy_test_config {
    /**
     * The size of the window to use for health tests, in bits.
     */
    uint16_t health_test_window;
  
    /**
     * The threshold for the repetition count test.
     */
    uint16_t rep_count_threshold;
  
    /**
     * The value range for the adaptive proportion test.
     *
     * The first value is the lower threshold; the second is the higher
     * threshold.
     */
    uint16_t adaptive_range[2];
  
    /**
     * The threshold for the bucket test.
     */
    uint16_t bucket_threshold;
  
    /**
     * The range for the "Markov" test.
     *
     * The first value is the lower threshold; the second is the higher
     * threshold.
     */
    uint16_t markov_range[2];
  
    /**
     * The value range for the vendor-specific test.
     *
     * The first value is the lower threshold; the second is the higher
     * threshold. However, vendors may interpret these values however they wish.
     */
    uint16_t vendor_range[2];
  } dif_entropy_test_config_t;
  
  /**
   * Hardware instantiation parameters for an entropy source.
   *
   * This struct describes information about the underlying hardware that is
   * not determined until the hardware design is used as part of a top-level
   * design.
   */
  typedef struct dif_entropy_params {
    /**
     * The base address for the entropy source hardware registers.
     */
    mmio_region_t base_addr;
  } dif_entropy_params_t;
  
  /**
   * Runtime configuration for an entropy source.
   *
   * This struct describes runtime information for one-time configuration of the
   * hardware.
   */
  typedef struct dif_entropy_config {
    /**
     * The mode to configure the entropy source in.
     */
    dif_entropy_mode_t mode;
  
    /**
     * Which health tests to enable.
     *
     * The variants of `dif_entropy_test` are used to index fields in this
     * array.
     *
     * Note that the value at `kDifEntropyTestMailbox` is ignored, since this test
     * is driven by the firmware, not the hardware.
     */
    bool tests[kDifEntropyTestNumVariants];
  
    /**
     * If set, all health-test-related registers will be cleared.
     */
    // TODO: Consider adding a separate setter for this config bit depending on
    // hardware behavior.
    bool reset_health_test_registers;
  
    /**
     * Specifies which single-bit-mode to use, if any at all.
     */
    dif_entropy_single_bit_mode_t single_bit_mode;
  
    /**
     * If set, entropy will be routed to a firmware-visible register instead of
     * being distributed to other hardware IPs.
     */
    // Open Question: Make this its own function? Seems like something that would
    // be toggled a lot.
    bool route_to_firmware;
  
    /**
     * If set, FIPS compliant entropy will be generated by this module after being
     * processed by an SP 800-90B compliant conditioning function.
     *
     * Software may opt for implementing FIPS mode of operation without hardware
     * support by setting this field to false. In such case, software is
     * responsible for implementing the conditioning function.
     */
    bool fips_mode;
  
    /**
     * Configuration parameters for health tests.
     */
    dif_entropy_test_config_t test_config;
  
    /**
     * The rate at which the entropy bits are generated, in clock cycles.
     */
    uint16_t sample_rate;
  
    /**
     * Seed used to load into the LFSR initial state. The maximum allowable value
     * is 15. See `dif_entropy_mode.kDifEntropyModeLfsr` for more details.
     */
    uint16_t lfsr_seed;
  } dif_entropy_config_t;
  
  /**
   * A handle to an entropy source.
   *
   * This type should be treated as opaque by users.
   */
  typedef struct dif_entropy {
    dif_entropy_params_t params;
  } dif_entropy_t;
  
  /**
   * Revision information for an entropy source.
   *
   * The fields of this struct have an implementation-specific interpretation.
   */
  typedef struct dif_entropy_revision {
    uint8_t abi_revision;
    uint8_t hw_revision;
    uint8_t chip_type;
  } dif_entropy_revision_t;
  
  /**
   * Statistics on entropy source health tests.
   */
  typedef struct dif_entropy_test_stats {
    /**
     * Watermarks indicating where the value emitted by a particular test has
     * ranged through; the low watermark is the lowest observed value, while the
     * high watermark is the highest.
     *
     * Each pair of watermarks is presented as a range from lowest to highest.
     */
    // TODO: Document behavior for repcnt and bucket tests.
    uint16_t watermarks[2][kDifEntropyTestNumVariants];
  
    /**
     * The number of times a particular test has failed.
     *
     * For tests that ensure the value lies in a range (such as the "Markov"
     * test), the array will contain the number of underflows and overflows of
     * this range, respectively; for tests that only have an upper range, the
     * first array element will be zeroed, and the second will be the number
     * of fails.
     *
     * For `dif_entropy_test.kDifEntropyTestRepCount` and
     * `dif_entropy_test.kDifEntropyTestBucket` the first array element will
     * be the number of fails, and the second will be zeroed.
     */
    uint32_t fails[2][kDifEntropyTestNumVariants];
  
    /**
     * The number of alerts emitted by a particular test.
     *
     * This has the same layout as `fails`.
     */
    uint8_t alerts[2][kDifEntropyTestNumVariants];
  } dif_entropy_test_stats_t;
  
  /**
   * The result of an entropy source operation.
   */
  typedef enum dif_entropy_result {
    /**
     * Indicates that the operation succeeded.
     */
    kDifEntropyOk = 0,
    /**
     * Indicates some unspecified failure.
     */
    kDifEntropyError = 1,
    /**
     * Indicates that some parameter passed into a function failed a
     * precondition.
     *
     * When this value is returned, no hardware operations occured.
     */
    kDifEntropyBadArg = 2,
    /**
     * Indicates that this operation has been locked out, and can never
     * succeed until hardware reset.
     */
    kDifEntropyLocked = 3,
    /**
     * Indicates that entropy is not yet available for software consumption
     */
    kDifEntropyDataUnAvailable = 4,
    /**
     * Indicates that entropy is not idle
     */
    kDifEntropyNotIdle = 5,
  } dif_entropy_result_t;
  
  /**
   * An entropy source interrupt request type.
   */
  typedef enum dif_entropy_irq {
    /**
     * Indicates that bits of entropy are available to consume.
     */
    kDifEntropyIrqAvailable,
  
    /**
     * Indicates that the health test has failed and the alert count has been
     * met.
     */
    kDifEntropyIrqUnhealthy,
  
    /**
     * Indicates that an internal error occured in the FIFO, or if an illegal
     * state machine state is reached.
     */
    kDifEntropyIrqFatalError,
  } dif_entropy_irq_t;
  
  /**
   * A snapshot of the enablement state of the interrupts for an entropy source.
   *
   * This is an opaque type, to be used with the `dif_entropy_irq_disable_all()`
   * and `dif_entropy_irq_restore_all()` functions.
   */
  typedef uint32_t dif_entropy_irq_snapshot_t;
  
  /**
   * An entropy source alert type.
   */
  typedef enum dif_entropy_alert {
    /**
     * Indicates that the health test criteria were not met.
     */
    kDifEntropyAlert,
  
    /**
     * Indicates that an internal error occurred.
     */
    kDifEntropyFatal,
  } dif_entropy_alert_t;
  
  /**
   * Creates a new handle for entropy source.
   *
   * This function does not actuate the hardware.
   *
   * @param params Hardware instantiation parameters.
   * @param[out] entropy Out param for the initialized handle.
   * @return The result of the operation.
   */
  DIF_WARN_UNUSED_RESULT
  dif_entropy_result_t dif_entropy_init(dif_entropy_params_t params,
                                        dif_entropy_t *entropy);
  
  /**
   * Configures entropy source with runtime information.
   *
   * This function should need to be called once for the lifetime of `handle`.
   *
   * @param entropy An entropy source handle.
   * @param config Runtime configuration parameters.
   * @return The result of the operation.
   */
  DIF_WARN_UNUSED_RESULT
  dif_entropy_result_t dif_entropy_configure(const dif_entropy_t *entropy,
                                             dif_entropy_config_t config);
  
  /**
   * Queries the entropy source IP for its revision information.
   *
   * @param entropy An entropy source handle.
   * @param[out] revision Out-param for revision data.
   * @return The result of the operation.
   */
  DIF_WARN_UNUSED_RESULT
  dif_entropy_result_t dif_entropy_get_revision(const dif_entropy_t *entropy,
                                                dif_entropy_revision_t *revision);
  
  /**
   * Queries the entropy source for health statistics.
   *
   * Calling this function also clears the relevant status registers.
   *
   * @param entropy An entropy source handle.
   * @param fips_mode The test mode to query statistics for.
   * @param[out] stats Out-param for stats data.
   * @return The result of the operation.
   */
  DIF_WARN_UNUSED_RESULT
  dif_entropy_result_t dif_entropy_get_stats(const dif_entropy_t *entropy,
                                             bool fips_mode,
                                             dif_entropy_test_stats_t *stats);
  
  /**
   * Locks out entropy source functionality.
   *
   * This function is reentrant: calling it while functionality is locked will
   * have no effect and return `kDifEntropyOk`.
   *
   * @param entropy An entropy source handle.
   * @return The result of the operation.
   */
  DIF_WARN_UNUSED_RESULT
  dif_entropy_result_t dif_entropy_lock(const dif_entropy_t *entropy);
  
  /**
   * Checks whether this entropy source is locked.
   *
   * @param entropy An entropy source handle.
   * @param[out] is_locked Out-param for the locked state.
   * @return The result of the operation.
   */
  DIF_WARN_UNUSED_RESULT
  dif_entropy_result_t dif_entropy_is_locked(const dif_entropy_t *entropy,
                                             bool *is_locked);
  
  /**
   * Checks to see if entropy is available for software consumption
   *
   * @param entropy An entropy source handle.
   * @return The result of the operation.
   */
  DIF_WARN_UNUSED_RESULT
  dif_entropy_result_t dif_entropy_avail(const dif_entropy_t *entropy);
  
  /**
   * Reads off a word of entropy from the entropy source.
   *
   * @param entropy An entropy source handle.
   * @param[out] word Out-param for the entropy.
   * @return The result of the operation.
   */
  DIF_WARN_UNUSED_RESULT
  dif_entropy_result_t dif_entropy_read(const dif_entropy_t *entropy,
                                        uint32_t *word);
  
  /**
   * Returns whether a particular interrupt is currently pending.
   *
   * @param entropy An entropy source handle.
   * @param irq An interrupt type.
   * @param[out] is_pending Out-param for whether the interrupt is pending.
   * @return The result of the operation.
   */
  DIF_WARN_UNUSED_RESULT
  dif_entropy_result_t dif_entropy_irq_is_pending(const dif_entropy_t *entropy,
                                                  dif_entropy_irq_t irq,
                                                  bool *is_pending);
  
  /**
   * Acknowledges a particular interrupt, indicating to the hardware that it has
   * been successfully serviced.
   *
   * @param entropy An entropy source handle.
   * @param irq An interrupt type.
   * @return The result of the operation.
   */
  DIF_WARN_UNUSED_RESULT
  dif_entropy_result_t dif_entropy_irq_acknowledge(const dif_entropy_t *entropy,
                                                   dif_entropy_irq_t irq);
  
  /**
   * Checks whether a particular interrupt is currently enabled or disabled.
   *
   * @param entropy An entropy source handle.
   * @param irq An interrupt type.
   * @param[out] state Out-param toggle state of the interrupt.
   * @return The result of the operation.
   */
  DIF_WARN_UNUSED_RESULT
  dif_entropy_result_t dif_entropy_irq_get_enabled(const dif_entropy_t *entropy,
                                                   dif_entropy_irq_t irq,
                                                   dif_entropy_toggle_t *state);
  
  /**
   * Sets whether a particular interrupt is currently enabled or disabled.
   *
   * @param entropy An entropy source handle.
   * @param irq An interrupt type.
   * @param state The new toggle state for the interrupt.
   * @return The result of the operation.
   */
  DIF_WARN_UNUSED_RESULT
  dif_entropy_result_t dif_entropy_irq_set_enabled(const dif_entropy_t *entropy,
                                                   dif_entropy_irq_t irq,
                                                   dif_entropy_toggle_t state);
  
  /**
   * Forces a particular interrupt, causing it to be serviced as if hardware had
   * asserted it.
   *
   * @param entropy An entropy source handle.
   * @param irq An interrupt type.
   * @return The result of the operation.
   */
  DIF_WARN_UNUSED_RESULT
  dif_entropy_result_t dif_entropy_irq_force(const dif_entropy_t *entropy,
                                             dif_entropy_irq_t irq);
  
  /**
   * Disables all interrupts, optionally snapshotting all toggle state for later
   * restoration.
   *
   * @param entropy An entropy source handle.
   * @param[out] snapshot Out-param for the snapshot; may be `NULL`.
   * @return The result of the operation.
   */
  DIF_WARN_UNUSED_RESULT
  dif_entropy_result_t dif_entropy_irq_disable_all(
      const dif_entropy_t *entropy, dif_entropy_irq_snapshot_t *snapshot);
  
  /**
   * Restores interrupts from the given snapshot.
   *
   * This function can be used with `dif_entropy_irq_disable_all()` to temporary
   * interrupt save-and-restore.
   *
   * @param entropy An entropy source handle.
   * @param snapshot A snapshot to restore from.
   * @return The result of the operation.
   */
  DIF_WARN_UNUSED_RESULT
  dif_entropy_result_t dif_entropy_irq_restore_all(
      const dif_entropy_t *entropy, const dif_entropy_irq_snapshot_t *snapshot);
  
  /**
   * Forces a particular alert, causing it to be emitted as if the hardware had
   * done so.
   *
   * @param entropy An entropy source handle.
   * @param alert An alert type.
   * @return The result of the operation.
   */
  DIF_WARN_UNUSED_RESULT
  dif_entropy_result_t dif_entropy_alert_force(const dif_entropy_t *entropy,
                                               dif_entropy_alert_t alert);
  
  /**
   * Performs an override read from the entropy pipeline.
   *
   * This function pauses entropy flow out of the pre-conditioner FIFO and
   * instead flows words into `buf`. Normal operation of the entropy pipeline
   * will not resume until `dif_entropy_fifo_reconnect()` is called.
   *
   * `buf` may be `NULL`; in this case, reads will be discarded.
   *
   * @param entropy An entropy source handle.
   * @param[out] buf A buffer to fill with words from the pipeline.
   * @param len The number of words to read into `buf`.
   * @return The result of the operation.
   */
  DIF_WARN_UNUSED_RESULT
  dif_entropy_result_t dif_entropy_fifo_read(const dif_entropy_t *entropy,
                                             uint32_t *buf, size_t len);
  
  /**
   * Performs an override write to the entropy pipeline.
   *
   * This function pauses entropy flow into the pre-conditioner FIFO and
   * instead flows words out of `buf`. Normal operation of the entropy pipeline
   * will not resume until `dif_entropy_fifo_reconnect()` is called.
   *
   * @param entropy An entropy source handle.
   * @param buf A buffer to push words from into the pipeline.
   * @param len The number of words to read from `buf`.
   * @return The result of the operation.
   */
  DIF_WARN_UNUSED_RESULT
  dif_entropy_result_t dif_entropy_fifo_write(const dif_entropy_t *entropy,
                                              const uint32_t *buf, size_t len);
  
  /**
   * Gets the current number of entries in the pre-conditioner FIFO.
   *
   * This function pauses the flow through the FIFO.
   *
   * @param entropy An entropy source handle.
   * @param[out] len The number of words in the FIFO.
   * @return The result of the operation.
   */
  DIF_WARN_UNUSED_RESULT
  dif_entropy_result_t dif_entropy_fifo_get_len(const dif_entropy_t *entropy,
                                                uint8_t *len);
  
  /**
   * Gets the current capacity of the pre-conditioner FIFO.
   *
   * @param entropy An entropy source handle.
   * @param[out] capacity The number of words of capacity in the FIFO.
   * @return The result of the operation.
   */
  DIF_WARN_UNUSED_RESULT
  dif_entropy_result_t dif_entropy_fifo_get_capacity(const dif_entropy_t *entropy,
                                                     uint8_t *capacity);
  
  /**
   * Sets the current capacity of the pre-conditioner FIFO.
   *
   * The `capacity` value must be less or equal to the physical capacity
   * of the fifo, defined as `kDifEntropyFifoMaxCapacity`.
   *
   * @param entropy An entropy source handle.
   * @param capacity The new capacity for the FIFO.
   * @return The result of the operation.
   */
  DIF_WARN_UNUSED_RESULT
  dif_entropy_result_t dif_entropy_fifo_set_capacity(const dif_entropy_t *entropy,
                                                     uint8_t capacity);
  
  /**
   * Reconnects the entropy pipeline after an operation that pauses it.
   *
   * This is a separate function call to avoid races between software and hardware
   * when performing multiple such operations, such as getting the length followed
   * by a read.
   *
   * @param entropy An entropy source handle.
   * @return The result of the operation.
   */
  DIF_WARN_UNUSED_RESULT
  dif_entropy_result_t dif_entropy_fifo_reconnect(const dif_entropy_t *entropy);
  
  /**
   * Disables the entropy module
   *
   * @param entropy An entropy source handle.
   * @return The result of the operation.
   */
  DIF_WARN_UNUSED_RESULT
  dif_entropy_result_t dif_entropy_disable(const dif_entropy_t *entropy);
  
  /**
   * Get main entropy fsm idle status
   *
   * @param entropy An entropy source handle.
   * @return The result of the operation.
   */
  DIF_WARN_UNUSED_RESULT
  dif_entropy_result_t dif_entropy_get_idle(const dif_entropy_t *entropy);
  
  #ifdef __cplusplus
  }  // extern "C"
  #endif  // __cplusplus
  
  #endif  // OPENTITAN_SW_DEVICE_LIB_DIF_DIF_ENTROPY_H_
  