|  | // Copyright lowRISC contributors. | 
|  | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | // SPDX-License-Identifier: Apache-2.0 | 
|  |  | 
|  | #include "sw/device/lib/dif/dif_csrng.h" | 
|  |  | 
|  | #include "sw/device/lib/base/bitfield.h" | 
|  | #include "sw/device/lib/base/macros.h" | 
|  | #include "sw/device/lib/base/memory.h" | 
|  | #include "sw/device/lib/base/mmio.h" | 
|  | #include "sw/device/lib/dif/dif_csrng_shared.h" | 
|  |  | 
|  | #include "csrng_regs.h"  // Generated | 
|  |  | 
|  | /** | 
|  | * Reads the output data register status. | 
|  | */ | 
|  | static void get_output_status(const dif_csrng_t *csrng, | 
|  | dif_csrng_output_status_t *status) { | 
|  | uint32_t reg = | 
|  | mmio_region_read32(csrng->base_addr, CSRNG_GENBITS_VLD_REG_OFFSET); | 
|  | status->valid_data = | 
|  | bitfield_bit32_read(reg, CSRNG_GENBITS_VLD_GENBITS_VLD_BIT); | 
|  | status->fips_mode = | 
|  | bitfield_bit32_read(reg, CSRNG_GENBITS_VLD_GENBITS_FIPS_BIT); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns true if the data register has valid data. | 
|  | */ | 
|  | static void spin_until_ready(const dif_csrng_t *csrng) { | 
|  | dif_csrng_output_status_t status; | 
|  | do { | 
|  | get_output_status(csrng, &status); | 
|  | } while (!status.valid_data); | 
|  | } | 
|  |  | 
|  | static dif_result_t check_locked(const dif_csrng_t *csrng) { | 
|  | if (mmio_region_read32(csrng->base_addr, CSRNG_REGWEN_REG_OFFSET) == 0) { | 
|  | return kDifLocked; | 
|  | } | 
|  | return kDifOk; | 
|  | } | 
|  |  | 
|  | dif_result_t dif_csrng_configure(const dif_csrng_t *csrng) { | 
|  | if (csrng == NULL) { | 
|  | return kDifBadArg; | 
|  | } | 
|  | DIF_RETURN_IF_ERROR(check_locked(csrng)); | 
|  |  | 
|  | uint32_t reg = | 
|  | bitfield_field32_write(0, CSRNG_CTRL_ENABLE_FIELD, kMultiBitBool4True); | 
|  | reg = bitfield_field32_write(reg, CSRNG_CTRL_SW_APP_ENABLE_FIELD, | 
|  | kMultiBitBool4True); | 
|  | reg = bitfield_field32_write(reg, CSRNG_CTRL_READ_INT_STATE_FIELD, | 
|  | kMultiBitBool4True); | 
|  | mmio_region_write32(csrng->base_addr, CSRNG_CTRL_REG_OFFSET, reg); | 
|  | return kDifOk; | 
|  | } | 
|  |  | 
|  | dif_result_t dif_csrng_instantiate( | 
|  | const dif_csrng_t *csrng, dif_csrng_entropy_src_toggle_t entropy_src_enable, | 
|  | const dif_csrng_seed_material_t *seed_material) { | 
|  | if (csrng == NULL || seed_material == NULL) { | 
|  | return kDifBadArg; | 
|  | } | 
|  | return csrng_send_app_cmd(csrng->base_addr, CSRNG_CMD_REQ_REG_OFFSET, | 
|  | (csrng_app_cmd_t){ | 
|  | .id = kCsrngAppCmdInstantiate, | 
|  | .entropy_src_enable = entropy_src_enable, | 
|  | .seed_material = seed_material, | 
|  | }); | 
|  | } | 
|  |  | 
|  | dif_result_t dif_csrng_reseed(const dif_csrng_t *csrng, | 
|  | const dif_csrng_seed_material_t *seed_material) { | 
|  | if (csrng == NULL || seed_material == NULL) { | 
|  | return kDifBadArg; | 
|  | } | 
|  | return csrng_send_app_cmd(csrng->base_addr, CSRNG_CMD_REQ_REG_OFFSET, | 
|  | (csrng_app_cmd_t){ | 
|  | .id = kCsrngAppCmdReseed, | 
|  | .seed_material = seed_material, | 
|  | }); | 
|  | } | 
|  |  | 
|  | dif_result_t dif_csrng_update(const dif_csrng_t *csrng, | 
|  | const dif_csrng_seed_material_t *seed_material) { | 
|  | if (csrng == NULL || seed_material == NULL) { | 
|  | return kDifBadArg; | 
|  | } | 
|  | return csrng_send_app_cmd(csrng->base_addr, CSRNG_CMD_REQ_REG_OFFSET, | 
|  | (csrng_app_cmd_t){ | 
|  | .id = kCsrngAppCmdUpdate, | 
|  | .seed_material = seed_material, | 
|  | }); | 
|  | } | 
|  |  | 
|  | dif_result_t dif_csrng_generate_start(const dif_csrng_t *csrng, size_t len) { | 
|  | if (csrng == NULL || len == 0) { | 
|  | return kDifBadArg; | 
|  | } | 
|  |  | 
|  | // Round up the number of 128bit blocks. Aligning with respect to uint32_t. | 
|  | // TODO(#6112): Consider using a canonical reference for alignment operations. | 
|  | const uint32_t num_128bit_blocks = (len + 3) / 4; | 
|  | return csrng_send_app_cmd(csrng->base_addr, CSRNG_CMD_REQ_REG_OFFSET, | 
|  | (csrng_app_cmd_t){ | 
|  | .id = kCsrngAppCmdGenerate, | 
|  | .generate_len = num_128bit_blocks, | 
|  | }); | 
|  | } | 
|  |  | 
|  | dif_result_t dif_csrng_generate_read(const dif_csrng_t *csrng, uint32_t *buf, | 
|  | size_t len) { | 
|  | if (csrng == NULL || buf == NULL) { | 
|  | return kDifBadArg; | 
|  | } | 
|  |  | 
|  | for (size_t i = 0; i < len; ++i) { | 
|  | // Block until there is more data available in the genbits buffer. | 
|  | if (i % kCsrngGenBitsBufferSize == 0) { | 
|  | spin_until_ready(csrng); | 
|  | } | 
|  | buf[i] = mmio_region_read32(csrng->base_addr, CSRNG_GENBITS_REG_OFFSET); | 
|  | } | 
|  | return kDifOk; | 
|  | } | 
|  |  | 
|  | dif_result_t dif_csrng_uninstantiate(const dif_csrng_t *csrng) { | 
|  | if (csrng == NULL) { | 
|  | return kDifBadArg; | 
|  | } | 
|  | return csrng_send_app_cmd(csrng->base_addr, CSRNG_CMD_REQ_REG_OFFSET, | 
|  | (csrng_app_cmd_t){ | 
|  | .id = kCsrngAppCmdUnisntantiate, | 
|  | }); | 
|  | } | 
|  |  | 
|  | dif_result_t dif_csrng_get_cmd_interface_status( | 
|  | const dif_csrng_t *csrng, dif_csrng_cmd_status_t *status) { | 
|  | if (csrng == NULL || status == NULL) { | 
|  | return kDifBadArg; | 
|  | } | 
|  | *status = (dif_csrng_cmd_status_t){0}; | 
|  |  | 
|  | uint32_t reg = | 
|  | mmio_region_read32(csrng->base_addr, CSRNG_SW_CMD_STS_REG_OFFSET); | 
|  | bool cmd_ready = bitfield_bit32_read(reg, CSRNG_SW_CMD_STS_CMD_RDY_BIT); | 
|  | bool cmd_error = bitfield_bit32_read(reg, CSRNG_SW_CMD_STS_CMD_STS_BIT); | 
|  |  | 
|  | // The function prioritizes error detection to avoid masking errors | 
|  | // when `cmd_ready` is set to true. | 
|  | if (cmd_error) { | 
|  | status->kind = kDifCsrngCmdStatusError; | 
|  | uint32_t reg = | 
|  | mmio_region_read32(csrng->base_addr, CSRNG_ERR_CODE_REG_OFFSET); | 
|  |  | 
|  | status->unhealthy_fifos = | 
|  | bitfield_bit32_copy(status->unhealthy_fifos, kDifCsrngFifoCmd, reg, | 
|  | CSRNG_ERR_CODE_SFIFO_CMD_ERR_BIT); | 
|  | status->unhealthy_fifos = | 
|  | bitfield_bit32_copy(status->unhealthy_fifos, kDifCsrngFifoGenBits, reg, | 
|  | CSRNG_ERR_CODE_SFIFO_GENBITS_ERR_BIT); | 
|  | status->unhealthy_fifos = | 
|  | bitfield_bit32_copy(status->unhealthy_fifos, kDifCsrngFifoCmdReq, reg, | 
|  | CSRNG_ERR_CODE_SFIFO_CMDREQ_ERR_BIT); | 
|  | status->unhealthy_fifos = | 
|  | bitfield_bit32_copy(status->unhealthy_fifos, kDifCsrngFifoRcStage, reg, | 
|  | CSRNG_ERR_CODE_SFIFO_RCSTAGE_ERR_BIT); | 
|  | status->unhealthy_fifos = | 
|  | bitfield_bit32_copy(status->unhealthy_fifos, kDifCsrngFifoKeyVrc, reg, | 
|  | CSRNG_ERR_CODE_SFIFO_KEYVRC_ERR_BIT); | 
|  | status->unhealthy_fifos = | 
|  | bitfield_bit32_copy(status->unhealthy_fifos, kDifCsrngFifoUpdateReq, | 
|  | reg, CSRNG_ERR_CODE_SFIFO_UPDREQ_ERR_BIT); | 
|  | status->unhealthy_fifos = | 
|  | bitfield_bit32_copy(status->unhealthy_fifos, kDifCsrngFifoBencRec, reg, | 
|  | CSRNG_ERR_CODE_SFIFO_BENCREQ_ERR_BIT); | 
|  | status->unhealthy_fifos = | 
|  | bitfield_bit32_copy(status->unhealthy_fifos, kDifCsrngFifoBencAck, reg, | 
|  | CSRNG_ERR_CODE_SFIFO_BENCACK_ERR_BIT); | 
|  | status->unhealthy_fifos = | 
|  | bitfield_bit32_copy(status->unhealthy_fifos, kDifCsrngFifoPData, reg, | 
|  | CSRNG_ERR_CODE_SFIFO_PDATA_ERR_BIT); | 
|  | status->unhealthy_fifos = | 
|  | bitfield_bit32_copy(status->unhealthy_fifos, kDifCsrngFifoFinal, reg, | 
|  | CSRNG_ERR_CODE_SFIFO_FINAL_ERR_BIT); | 
|  | status->unhealthy_fifos = | 
|  | bitfield_bit32_copy(status->unhealthy_fifos, kDifCsrngFifoGBencAck, reg, | 
|  | CSRNG_ERR_CODE_SFIFO_GBENCACK_ERR_BIT); | 
|  | status->unhealthy_fifos = | 
|  | bitfield_bit32_copy(status->unhealthy_fifos, kDifCsrngFifoGrcStage, reg, | 
|  | CSRNG_ERR_CODE_SFIFO_GRCSTAGE_ERR_BIT); | 
|  | status->unhealthy_fifos = | 
|  | bitfield_bit32_copy(status->unhealthy_fifos, kDifCsrngFifoGGenReq, reg, | 
|  | CSRNG_ERR_CODE_SFIFO_GGENREQ_ERR_BIT); | 
|  | status->unhealthy_fifos = | 
|  | bitfield_bit32_copy(status->unhealthy_fifos, kDifCsrngFifoGadStage, reg, | 
|  | CSRNG_ERR_CODE_SFIFO_GADSTAGE_ERR_BIT); | 
|  | status->unhealthy_fifos = | 
|  | bitfield_bit32_copy(status->unhealthy_fifos, kDifCsrngFifoBlockEnc, reg, | 
|  | CSRNG_ERR_CODE_SFIFO_BLKENC_ERR_BIT); | 
|  |  | 
|  | status->errors = | 
|  | bitfield_bit32_copy(status->errors, kDifCsrngErrorCmdStageSm, reg, | 
|  | CSRNG_ERR_CODE_CMD_STAGE_SM_ERR_BIT); | 
|  | status->errors = bitfield_bit32_copy(status->errors, kDifCsrngErrorMainSm, | 
|  | reg, CSRNG_ERR_CODE_MAIN_SM_ERR_BIT); | 
|  | status->errors = | 
|  | bitfield_bit32_copy(status->errors, kDifCsrngErrorDrbgGenSm, reg, | 
|  | CSRNG_ERR_CODE_DRBG_GEN_SM_ERR_BIT); | 
|  | status->errors = | 
|  | bitfield_bit32_copy(status->errors, kDifCsrngErrorDrbgUpdateBlockEncSm, | 
|  | reg, CSRNG_ERR_CODE_DRBG_UPDBE_SM_ERR_BIT); | 
|  | status->errors = | 
|  | bitfield_bit32_copy(status->errors, kDifCsrngErrorDrbgUpdateOutBlockSm, | 
|  | reg, CSRNG_ERR_CODE_DRBG_UPDOB_SM_ERR_BIT); | 
|  | status->errors = | 
|  | bitfield_bit32_copy(status->errors, kDifCsrngErrorAesSm, reg, | 
|  | CSRNG_ERR_CODE_AES_CIPHER_SM_ERR_BIT); | 
|  | status->errors = | 
|  | bitfield_bit32_copy(status->errors, kDifCsrngErrorGenerateCmdCounter, | 
|  | reg, CSRNG_ERR_CODE_CMD_GEN_CNT_ERR_BIT); | 
|  | status->errors = | 
|  | bitfield_bit32_copy(status->errors, kDifCsrngErrorFifoWrite, reg, | 
|  | CSRNG_ERR_CODE_FIFO_WRITE_ERR_BIT); | 
|  | status->errors = bitfield_bit32_copy(status->errors, kDifCsrngErrorFifoRead, | 
|  | reg, CSRNG_ERR_CODE_FIFO_READ_ERR_BIT); | 
|  | status->errors = | 
|  | bitfield_bit32_copy(status->errors, kDifCsrngErrorFifoFullAndEmpty, reg, | 
|  | CSRNG_ERR_CODE_FIFO_STATE_ERR_BIT); | 
|  |  | 
|  | return kDifOk; | 
|  | } | 
|  |  | 
|  | if (cmd_ready) { | 
|  | status->kind = kDifCsrngCmdStatusReady; | 
|  | return kDifOk; | 
|  | } | 
|  |  | 
|  | status->kind = kDifCsrngCmdStatusBusy; | 
|  | return kDifOk; | 
|  | } | 
|  |  | 
|  | dif_result_t dif_csrng_get_cmd_force_unhealthy_fifo(const dif_csrng_t *csrng, | 
|  | dif_csrng_fifo_t fifo) { | 
|  | if (csrng == NULL) { | 
|  | return kDifBadArg; | 
|  | } | 
|  |  | 
|  | uint32_t fifo_bit; | 
|  | switch (fifo) { | 
|  | case kDifCsrngFifoCmd: | 
|  | fifo_bit = CSRNG_ERR_CODE_SFIFO_CMD_ERR_BIT; | 
|  | break; | 
|  | case kDifCsrngFifoGenBits: | 
|  | fifo_bit = CSRNG_ERR_CODE_SFIFO_GENBITS_ERR_BIT; | 
|  | break; | 
|  | case kDifCsrngFifoCmdReq: | 
|  | fifo_bit = CSRNG_ERR_CODE_SFIFO_CMDREQ_ERR_BIT; | 
|  | break; | 
|  | case kDifCsrngFifoRcStage: | 
|  | fifo_bit = CSRNG_ERR_CODE_SFIFO_RCSTAGE_ERR_BIT; | 
|  | break; | 
|  | case kDifCsrngFifoKeyVrc: | 
|  | fifo_bit = CSRNG_ERR_CODE_SFIFO_KEYVRC_ERR_BIT; | 
|  | break; | 
|  | case kDifCsrngFifoUpdateReq: | 
|  | fifo_bit = CSRNG_ERR_CODE_SFIFO_UPDREQ_ERR_BIT; | 
|  | break; | 
|  | case kDifCsrngFifoBencRec: | 
|  | fifo_bit = CSRNG_ERR_CODE_SFIFO_BENCREQ_ERR_BIT; | 
|  | break; | 
|  | case kDifCsrngFifoBencAck: | 
|  | fifo_bit = CSRNG_ERR_CODE_SFIFO_BENCACK_ERR_BIT; | 
|  | break; | 
|  | case kDifCsrngFifoPData: | 
|  | fifo_bit = CSRNG_ERR_CODE_SFIFO_PDATA_ERR_BIT; | 
|  | break; | 
|  | case kDifCsrngFifoFinal: | 
|  | fifo_bit = CSRNG_ERR_CODE_SFIFO_FINAL_ERR_BIT; | 
|  | break; | 
|  | case kDifCsrngFifoGBencAck: | 
|  | fifo_bit = CSRNG_ERR_CODE_SFIFO_GBENCACK_ERR_BIT; | 
|  | break; | 
|  | case kDifCsrngFifoGrcStage: | 
|  | fifo_bit = CSRNG_ERR_CODE_SFIFO_GRCSTAGE_ERR_BIT; | 
|  | break; | 
|  | case kDifCsrngFifoGGenReq: | 
|  | fifo_bit = CSRNG_ERR_CODE_SFIFO_GGENREQ_ERR_BIT; | 
|  | break; | 
|  | case kDifCsrngFifoGadStage: | 
|  | fifo_bit = CSRNG_ERR_CODE_SFIFO_GADSTAGE_ERR_BIT; | 
|  | break; | 
|  | case kDifCsrngFifoBlockEnc: | 
|  | fifo_bit = CSRNG_ERR_CODE_SFIFO_BLKENC_ERR_BIT; | 
|  | break; | 
|  | default: | 
|  | return kDifBadArg; | 
|  | } | 
|  |  | 
|  | DIF_RETURN_IF_ERROR(check_locked(csrng)); | 
|  | mmio_region_write32(csrng->base_addr, CSRNG_ERR_CODE_TEST_REG_OFFSET, | 
|  | fifo_bit); | 
|  | return kDifOk; | 
|  | } | 
|  |  | 
|  | dif_result_t dif_csrng_get_cmd_force_error(const dif_csrng_t *csrng, | 
|  | dif_csrng_error_t error) { | 
|  | if (csrng == NULL) { | 
|  | return kDifBadArg; | 
|  | } | 
|  |  | 
|  | uint32_t error_bit; | 
|  | switch (error) { | 
|  | case kDifCsrngErrorCmdStageSm: | 
|  | error_bit = CSRNG_ERR_CODE_CMD_STAGE_SM_ERR_BIT; | 
|  | break; | 
|  | case kDifCsrngErrorMainSm: | 
|  | error_bit = CSRNG_ERR_CODE_MAIN_SM_ERR_BIT; | 
|  | break; | 
|  | case kDifCsrngErrorDrbgGenSm: | 
|  | error_bit = CSRNG_ERR_CODE_DRBG_GEN_SM_ERR_BIT; | 
|  | break; | 
|  | case kDifCsrngErrorDrbgUpdateBlockEncSm: | 
|  | error_bit = CSRNG_ERR_CODE_DRBG_UPDBE_SM_ERR_BIT; | 
|  | break; | 
|  | case kDifCsrngErrorDrbgUpdateOutBlockSm: | 
|  | error_bit = CSRNG_ERR_CODE_DRBG_UPDOB_SM_ERR_BIT; | 
|  | break; | 
|  | case kDifCsrngErrorAesSm: | 
|  | error_bit = CSRNG_ERR_CODE_AES_CIPHER_SM_ERR_BIT; | 
|  | break; | 
|  | case kDifCsrngErrorGenerateCmdCounter: | 
|  | error_bit = CSRNG_ERR_CODE_CMD_GEN_CNT_ERR_BIT; | 
|  | break; | 
|  | case kDifCsrngErrorFifoWrite: | 
|  | error_bit = CSRNG_ERR_CODE_FIFO_WRITE_ERR_BIT; | 
|  | break; | 
|  | case kDifCsrngErrorFifoRead: | 
|  | error_bit = CSRNG_ERR_CODE_FIFO_READ_ERR_BIT; | 
|  | break; | 
|  | case kDifCsrngErrorFifoFullAndEmpty: | 
|  | error_bit = CSRNG_ERR_CODE_FIFO_STATE_ERR_BIT; | 
|  | break; | 
|  | default: | 
|  | return kDifBadArg; | 
|  | } | 
|  |  | 
|  | DIF_RETURN_IF_ERROR(check_locked(csrng)); | 
|  | mmio_region_write32(csrng->base_addr, CSRNG_ERR_CODE_TEST_REG_OFFSET, | 
|  | error_bit); | 
|  | return kDifOk; | 
|  | } | 
|  |  | 
|  | dif_result_t dif_csrng_get_main_state_machine(const dif_csrng_t *csrng, | 
|  | uint32_t *state) { | 
|  | if (csrng == NULL || state == NULL) { | 
|  | return kDifBadArg; | 
|  | } | 
|  |  | 
|  | *state = mmio_region_read32(csrng->base_addr, CSRNG_MAIN_SM_STATE_REG_OFFSET); | 
|  | return kDifOk; | 
|  | } | 
|  |  | 
|  | dif_result_t dif_csrng_get_hw_csrng_exceptions(const dif_csrng_t *csrng, | 
|  | uint32_t *exceptions) { | 
|  | if (csrng == NULL || exceptions == NULL) { | 
|  | return kDifBadArg; | 
|  | } | 
|  |  | 
|  | *exceptions = | 
|  | mmio_region_read32(csrng->base_addr, CSRNG_HW_EXC_STS_REG_OFFSET); | 
|  | return kDifOk; | 
|  | } | 
|  |  | 
|  | dif_result_t dif_csrng_clear_hw_csrng_exceptions(const dif_csrng_t *csrng) { | 
|  | if (csrng == NULL) { | 
|  | return kDifBadArg; | 
|  | } | 
|  |  | 
|  | mmio_region_write32(csrng->base_addr, CSRNG_HW_EXC_STS_REG_OFFSET, 0); | 
|  | return kDifOk; | 
|  | } | 
|  |  | 
|  | dif_result_t dif_csrng_get_output_status(const dif_csrng_t *csrng, | 
|  | dif_csrng_output_status_t *status) { | 
|  | if (csrng == NULL || status == NULL) { | 
|  | return kDifBadArg; | 
|  | } | 
|  | get_output_status(csrng, status); | 
|  | return kDifOk; | 
|  | } | 
|  |  | 
|  | dif_result_t dif_csrng_get_internal_state( | 
|  | const dif_csrng_t *csrng, dif_csrng_internal_state_id_t instance_id, | 
|  | dif_csrng_internal_state_t *state) { | 
|  | if (csrng == NULL || state == NULL) { | 
|  | return kDifBadArg; | 
|  | } | 
|  |  | 
|  | // Select the instance id to read the internal state from, request a state | 
|  | // machine halt, and wait for the internal registers to be ready to be read. | 
|  | uint32_t reg = bitfield_field32_write( | 
|  | 0, CSRNG_INT_STATE_NUM_INT_STATE_NUM_FIELD, instance_id); | 
|  | mmio_region_write32(csrng->base_addr, CSRNG_INT_STATE_NUM_REG_OFFSET, reg); | 
|  |  | 
|  | // Read the internal state. | 
|  | state->reseed_counter = | 
|  | mmio_region_read32(csrng->base_addr, CSRNG_INT_STATE_VAL_REG_OFFSET); | 
|  |  | 
|  | for (size_t i = 0; i < ARRAYSIZE(state->v); ++i) { | 
|  | state->v[i] = | 
|  | mmio_region_read32(csrng->base_addr, CSRNG_INT_STATE_VAL_REG_OFFSET); | 
|  | } | 
|  |  | 
|  | for (size_t i = 0; i < ARRAYSIZE(state->key); ++i) { | 
|  | state->key[i] = | 
|  | mmio_region_read32(csrng->base_addr, CSRNG_INT_STATE_VAL_REG_OFFSET); | 
|  | } | 
|  |  | 
|  | uint32_t flags = | 
|  | mmio_region_read32(csrng->base_addr, CSRNG_INT_STATE_VAL_REG_OFFSET); | 
|  |  | 
|  | // The following bit indexes are defined in | 
|  | // https://docs.opentitan.org/hw/ip/csrng/doc/#working-state-values | 
|  | state->instantiated = bitfield_bit32_read(flags, /*bit_index=*/0u); | 
|  | state->fips_compliance = bitfield_bit32_read(flags, /*bit_index=*/1u); | 
|  |  | 
|  | return kDifOk; | 
|  | } | 
|  |  | 
|  | dif_result_t dif_csrng_lock(const dif_csrng_t *csrng) { | 
|  | if (csrng == NULL) { | 
|  | return kDifBadArg; | 
|  | } | 
|  | mmio_region_write32(csrng->base_addr, CSRNG_REGWEN_REG_OFFSET, 0); | 
|  | return kDifOk; | 
|  | } | 
|  |  | 
|  | dif_result_t dif_csrng_is_locked(const dif_csrng_t *csrng, bool *is_locked) { | 
|  | if (csrng == NULL || is_locked == NULL) { | 
|  | return kDifBadArg; | 
|  | } | 
|  | *is_locked = check_locked(csrng) != kDifOk; | 
|  | return kDifOk; | 
|  | } | 
|  |  | 
|  | dif_result_t dif_csrng_stop(const dif_csrng_t *csrng) { | 
|  | if (csrng == NULL) { | 
|  | return kDifBadArg; | 
|  | } | 
|  | DIF_RETURN_IF_ERROR(check_locked(csrng)); | 
|  | mmio_region_write32(csrng->base_addr, CSRNG_CTRL_REG_OFFSET, | 
|  | CSRNG_CTRL_REG_RESVAL); | 
|  | return kDifOk; | 
|  | } | 
|  |  | 
|  | dif_result_t dif_csrng_get_recoverable_alerts(const dif_csrng_t *csrng, | 
|  | uint32_t *alerts) { | 
|  | if (csrng == NULL || alerts == NULL) { | 
|  | return kDifBadArg; | 
|  | } | 
|  |  | 
|  | *alerts = 0; | 
|  | uint32_t reg = | 
|  | mmio_region_read32(csrng->base_addr, CSRNG_RECOV_ALERT_STS_REG_OFFSET); | 
|  | *alerts = | 
|  | bitfield_bit32_copy(*alerts, kDifCsrngRecoverableAlertBadEnable, reg, | 
|  | CSRNG_RECOV_ALERT_STS_ENABLE_FIELD_ALERT_BIT); | 
|  | *alerts = | 
|  | bitfield_bit32_copy(*alerts, kDifCsrngRecoverableAlertBadSwAppEnable, reg, | 
|  | CSRNG_RECOV_ALERT_STS_SW_APP_ENABLE_FIELD_ALERT_BIT); | 
|  | *alerts = | 
|  | bitfield_bit32_copy(*alerts, kDifCsrngRecoverableAlertBadIntState, reg, | 
|  | CSRNG_RECOV_ALERT_STS_READ_INT_STATE_FIELD_ALERT_BIT); | 
|  | *alerts = | 
|  | bitfield_bit32_copy(*alerts, kDifCsrngRecoverableAlertRepeatedGenBits, | 
|  | reg, CSRNG_RECOV_ALERT_STS_CS_BUS_CMP_ALERT_BIT); | 
|  | return kDifOk; | 
|  | } | 
|  |  | 
|  | dif_result_t dif_csrng_clear_recoverable_alerts(const dif_csrng_t *csrng) { | 
|  | if (csrng == NULL) { | 
|  | return kDifBadArg; | 
|  | } | 
|  | mmio_region_write32(csrng->base_addr, CSRNG_RECOV_ALERT_STS_REG_OFFSET, 0); | 
|  | return kDifOk; | 
|  | } |