| // 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_keymgr.h" | 
 |  | 
 | #include <assert.h> | 
 |  | 
 | #include "sw/device/lib/dif/dif_base.h" | 
 |  | 
 | #include "keymgr_regs.h"  // Generated. | 
 | #include "sw/device/lib/dif/autogen/dif_keymgr_autogen.h" | 
 |  | 
 | /** | 
 |  * Address spaces of SEALING_SW_BINDING_N, SALT_N, SW_SHARE0_OUTPUT_N, and | 
 |  * SW_SHARE1_OUTPUT_N registers must be contiguous to be able to use | 
 |  * `mmio_region_memcpy_to/from_mmio32()`. | 
 |  */ | 
 | static_assert(KEYMGR_SEALING_SW_BINDING_1_REG_OFFSET == | 
 |                   KEYMGR_SEALING_SW_BINDING_0_REG_OFFSET + 4, | 
 |               "SEALING_SW_BINDING_N registers must be contiguous."); | 
 | static_assert(KEYMGR_SEALING_SW_BINDING_2_REG_OFFSET == | 
 |                   KEYMGR_SEALING_SW_BINDING_0_REG_OFFSET + 8, | 
 |               "SEALING_SW_BINDING_N registers must be contiguous."); | 
 | static_assert(KEYMGR_SEALING_SW_BINDING_3_REG_OFFSET == | 
 |                   KEYMGR_SEALING_SW_BINDING_0_REG_OFFSET + 12, | 
 |               "SEALING_SW_BINDING_N registers must be contiguous."); | 
 | static_assert(KEYMGR_SEALING_SW_BINDING_4_REG_OFFSET == | 
 |                   KEYMGR_SEALING_SW_BINDING_0_REG_OFFSET + 16, | 
 |               "SEALING_SW_BINDING_N registers must be contiguous."); | 
 | static_assert(KEYMGR_SEALING_SW_BINDING_5_REG_OFFSET == | 
 |                   KEYMGR_SEALING_SW_BINDING_0_REG_OFFSET + 20, | 
 |               "SEALING_SW_BINDING_N registers must be contiguous."); | 
 | static_assert(KEYMGR_SEALING_SW_BINDING_6_REG_OFFSET == | 
 |                   KEYMGR_SEALING_SW_BINDING_0_REG_OFFSET + 24, | 
 |               "SEALING_SW_BINDING_N registers must be contiguous."); | 
 | static_assert(KEYMGR_SEALING_SW_BINDING_7_REG_OFFSET == | 
 |                   KEYMGR_SEALING_SW_BINDING_0_REG_OFFSET + 28, | 
 |               "SEALING_SW_BINDING_N registers must be contiguous."); | 
 |  | 
 | static_assert(KEYMGR_SALT_1_REG_OFFSET == KEYMGR_SALT_0_REG_OFFSET + 4, | 
 |               "SALT_N registers must be contiguous."); | 
 | static_assert(KEYMGR_SALT_2_REG_OFFSET == KEYMGR_SALT_0_REG_OFFSET + 8, | 
 |               "SALT_N registers must be contiguous."); | 
 | static_assert(KEYMGR_SALT_3_REG_OFFSET == KEYMGR_SALT_0_REG_OFFSET + 12, | 
 |               "SALT_N registers must be contiguous."); | 
 | static_assert(KEYMGR_SALT_4_REG_OFFSET == KEYMGR_SALT_0_REG_OFFSET + 16, | 
 |               "SALT_N registers must be contiguous."); | 
 | static_assert(KEYMGR_SALT_5_REG_OFFSET == KEYMGR_SALT_0_REG_OFFSET + 20, | 
 |               "SALT_N registers must be contiguous."); | 
 | static_assert(KEYMGR_SALT_6_REG_OFFSET == KEYMGR_SALT_0_REG_OFFSET + 24, | 
 |               "SALT_N registers must be contiguous."); | 
 | static_assert(KEYMGR_SALT_7_REG_OFFSET == KEYMGR_SALT_0_REG_OFFSET + 28, | 
 |               "SALT_N registers must be contiguous."); | 
 |  | 
 | static_assert(KEYMGR_SW_SHARE0_OUTPUT_1_REG_OFFSET == | 
 |                   KEYMGR_SW_SHARE0_OUTPUT_0_REG_OFFSET + 4, | 
 |               "SW_SHARE0_OUTPUT_N registers must be contiguous."); | 
 | static_assert(KEYMGR_SW_SHARE0_OUTPUT_2_REG_OFFSET == | 
 |                   KEYMGR_SW_SHARE0_OUTPUT_0_REG_OFFSET + 8, | 
 |               "SW_SHARE0_OUTPUT_N registers must be contiguous."); | 
 | static_assert(KEYMGR_SW_SHARE0_OUTPUT_3_REG_OFFSET == | 
 |                   KEYMGR_SW_SHARE0_OUTPUT_0_REG_OFFSET + 12, | 
 |               "SW_SHARE0_OUTPUT_N registers must be contiguous."); | 
 | static_assert(KEYMGR_SW_SHARE0_OUTPUT_4_REG_OFFSET == | 
 |                   KEYMGR_SW_SHARE0_OUTPUT_0_REG_OFFSET + 16, | 
 |               "SW_SHARE0_OUTPUT_N registers must be contiguous."); | 
 | static_assert(KEYMGR_SW_SHARE0_OUTPUT_5_REG_OFFSET == | 
 |                   KEYMGR_SW_SHARE0_OUTPUT_0_REG_OFFSET + 20, | 
 |               "SW_SHARE0_OUTPUT_N registers must be contiguous."); | 
 | static_assert(KEYMGR_SW_SHARE0_OUTPUT_6_REG_OFFSET == | 
 |                   KEYMGR_SW_SHARE0_OUTPUT_0_REG_OFFSET + 24, | 
 |               "SW_SHARE0_OUTPUT_N registers must be contiguous."); | 
 | static_assert(KEYMGR_SW_SHARE0_OUTPUT_7_REG_OFFSET == | 
 |                   KEYMGR_SW_SHARE0_OUTPUT_0_REG_OFFSET + 28, | 
 |               "SW_SHARE0_OUTPUT_N registers must be contiguous."); | 
 |  | 
 | static_assert(KEYMGR_SW_SHARE1_OUTPUT_1_REG_OFFSET == | 
 |                   KEYMGR_SW_SHARE1_OUTPUT_0_REG_OFFSET + 4, | 
 |               "SW_SHARE1_OUTPUT_N registers must be contiguous."); | 
 | static_assert(KEYMGR_SW_SHARE1_OUTPUT_2_REG_OFFSET == | 
 |                   KEYMGR_SW_SHARE1_OUTPUT_0_REG_OFFSET + 8, | 
 |               "SW_SHARE1_OUTPUT_N registers must be contiguous."); | 
 | static_assert(KEYMGR_SW_SHARE1_OUTPUT_3_REG_OFFSET == | 
 |                   KEYMGR_SW_SHARE1_OUTPUT_0_REG_OFFSET + 12, | 
 |               "SW_SHARE1_OUTPUT_N registers must be contiguous."); | 
 | static_assert(KEYMGR_SW_SHARE1_OUTPUT_4_REG_OFFSET == | 
 |                   KEYMGR_SW_SHARE1_OUTPUT_0_REG_OFFSET + 16, | 
 |               "SW_SHARE1_OUTPUT_N registers must be contiguous."); | 
 | static_assert(KEYMGR_SW_SHARE1_OUTPUT_5_REG_OFFSET == | 
 |                   KEYMGR_SW_SHARE1_OUTPUT_0_REG_OFFSET + 20, | 
 |               "SW_SHARE1_OUTPUT_N registers must be contiguous."); | 
 | static_assert(KEYMGR_SW_SHARE1_OUTPUT_6_REG_OFFSET == | 
 |                   KEYMGR_SW_SHARE1_OUTPUT_0_REG_OFFSET + 24, | 
 |               "SW_SHARE1_OUTPUT_N registers must be contiguous."); | 
 | static_assert(KEYMGR_SW_SHARE1_OUTPUT_7_REG_OFFSET == | 
 |                   KEYMGR_SW_SHARE1_OUTPUT_0_REG_OFFSET + 28, | 
 |               "SW_SHARE1_OUTPUT_N registers must be contiguous."); | 
 |  | 
 | /** | 
 |  * Error code constants of `dif_keymgr_status_code_t` are masks for the bits of | 
 |  * ERR_CODE register shifted left by 1. | 
 |  */ | 
 | static_assert(kDifKeymgrStatusCodeInvalidOperation >> 1 == | 
 |                   1 << KEYMGR_ERR_CODE_INVALID_OP_BIT, | 
 |               "Layout of ERR_CODE register changed."); | 
 | static_assert(kDifKeymgrStatusCodeInvalidKmacInput >> 1 == | 
 |                   1 << KEYMGR_ERR_CODE_INVALID_KMAC_INPUT_BIT, | 
 |               "Layout of ERR_CODE register changed."); | 
 |  | 
 | /** | 
 |  * Checks if the key manager is ready for a new operation, i.e. it is idle and | 
 |  * the CONFIG register is unlocked. | 
 |  */ | 
 | OT_WARN_UNUSED_RESULT | 
 | static bool is_ready(const dif_keymgr_t *keymgr) { | 
 |   // Keymgr must be idle and the CONTROL register must be writable. | 
 |   uint32_t reg_op_status = | 
 |       mmio_region_read32(keymgr->base_addr, KEYMGR_OP_STATUS_REG_OFFSET); | 
 |   if (bitfield_field32_read(reg_op_status, KEYMGR_OP_STATUS_STATUS_FIELD) != | 
 |       KEYMGR_OP_STATUS_STATUS_VALUE_IDLE) { | 
 |     return false; | 
 |   } | 
 |   uint32_t reg_cfg_regwen = | 
 |       mmio_region_read32(keymgr->base_addr, KEYMGR_CFG_REGWEN_REG_OFFSET); | 
 |   return bitfield_bit32_read(reg_cfg_regwen, KEYMGR_CFG_REGWEN_EN_BIT); | 
 | } | 
 |  | 
 | /** | 
 |  * Max key version register information for a state transition. | 
 |  */ | 
 | typedef struct max_key_version_reg_info { | 
 |   /** | 
 |    * Whether max key version must be set for this transition or not. | 
 |    */ | 
 |   bool is_required; | 
 |   /** | 
 |    * Max key version register offset to use. | 
 |    */ | 
 |   uint32_t reg_offset; | 
 |   /** | 
 |    * Write-enable register offset to use. | 
 |    */ | 
 |   uint32_t wen_reg_offset; | 
 |   /** | 
 |    * Write-enable bit index. | 
 |    */ | 
 |   bitfield_bit32_index_t wen_bit_index; | 
 | } max_key_version_reg_info_t; | 
 |  | 
 | /** | 
 |  * Returns max key version register information for transitioning from a state. | 
 |  */ | 
 | OT_WARN_UNUSED_RESULT | 
 | static bool get_max_key_version_reg_info_for_next_state( | 
 |     uint32_t cur_state, max_key_version_reg_info_t *reg_info) { | 
 |   switch (cur_state) { | 
 |     case KEYMGR_WORKING_STATE_STATE_VALUE_INIT: | 
 |       *reg_info = (max_key_version_reg_info_t){ | 
 |           .is_required = true, | 
 |           .reg_offset = KEYMGR_MAX_CREATOR_KEY_VER_SHADOWED_REG_OFFSET, | 
 |           .wen_reg_offset = KEYMGR_MAX_CREATOR_KEY_VER_REGWEN_REG_OFFSET, | 
 |           .wen_bit_index = KEYMGR_MAX_CREATOR_KEY_VER_REGWEN_EN_BIT, | 
 |       }; | 
 |       return true; | 
 |     case KEYMGR_WORKING_STATE_STATE_VALUE_CREATOR_ROOT_KEY: | 
 |       *reg_info = (max_key_version_reg_info_t){ | 
 |           .is_required = true, | 
 |           .reg_offset = KEYMGR_MAX_OWNER_INT_KEY_VER_SHADOWED_REG_OFFSET, | 
 |           .wen_reg_offset = KEYMGR_MAX_OWNER_INT_KEY_VER_REGWEN_REG_OFFSET, | 
 |           .wen_bit_index = KEYMGR_MAX_OWNER_INT_KEY_VER_REGWEN_EN_BIT, | 
 |       }; | 
 |       return true; | 
 |     case KEYMGR_WORKING_STATE_STATE_VALUE_OWNER_INTERMEDIATE_KEY: | 
 |       *reg_info = (max_key_version_reg_info_t){ | 
 |           .is_required = true, | 
 |           .reg_offset = KEYMGR_MAX_OWNER_KEY_VER_SHADOWED_REG_OFFSET, | 
 |           .wen_reg_offset = KEYMGR_MAX_OWNER_KEY_VER_REGWEN_REG_OFFSET, | 
 |           .wen_bit_index = KEYMGR_MAX_OWNER_KEY_VER_REGWEN_EN_BIT, | 
 |       }; | 
 |       return true; | 
 |     case KEYMGR_WORKING_STATE_STATE_VALUE_RESET: | 
 |     case KEYMGR_WORKING_STATE_STATE_VALUE_OWNER_KEY: | 
 |     case KEYMGR_WORKING_STATE_STATE_VALUE_DISABLED: | 
 |     case KEYMGR_WORKING_STATE_STATE_VALUE_INVALID: | 
 |       *reg_info = (max_key_version_reg_info_t){ | 
 |           .is_required = false, | 
 |       }; | 
 |       return true; | 
 |     default: | 
 |       return false; | 
 |   } | 
 | } | 
 |  | 
 | /** | 
 |  * Parameters for starting a key manager operation. | 
 |  * | 
 |  * Values of the members must be the actual values that will be written to the | 
 |  * CONTROL register. | 
 |  */ | 
 | typedef struct start_operation_params { | 
 |   /** | 
 |    * Destination for this operation. | 
 |    */ | 
 |   uint32_t dest; | 
 |   /** | 
 |    * Operation to start. | 
 |    */ | 
 |   uint32_t op; | 
 | } start_operation_params_t; | 
 |  | 
 | /** | 
 |  * Starts a key manager operation. | 
 |  */ | 
 | static void start_operation(const dif_keymgr_t *keymgr, | 
 |                             start_operation_params_t params) { | 
 |   uint32_t reg_control = bitfield_field32_write( | 
 |       0, KEYMGR_CONTROL_SHADOWED_DEST_SEL_FIELD, params.dest); | 
 |   reg_control = bitfield_field32_write( | 
 |       reg_control, KEYMGR_CONTROL_SHADOWED_OPERATION_FIELD, params.op); | 
 |   mmio_region_write32_shadowed(keymgr->base_addr, | 
 |                                KEYMGR_CONTROL_SHADOWED_REG_OFFSET, reg_control); | 
 |   mmio_region_write32(keymgr->base_addr, KEYMGR_START_REG_OFFSET, | 
 |                       1 << KEYMGR_START_EN_BIT); | 
 | } | 
 |  | 
 | dif_result_t dif_keymgr_configure(const dif_keymgr_t *keymgr, | 
 |                                   dif_keymgr_config_t config) { | 
 |   if (keymgr == NULL) { | 
 |     return kDifBadArg; | 
 |   } | 
 |  | 
 |   uint32_t reg_val = | 
 |       bitfield_field32_write(0, KEYMGR_RESEED_INTERVAL_SHADOWED_VAL_FIELD, | 
 |                              config.entropy_reseed_interval); | 
 |   mmio_region_write32_shadowed( | 
 |       keymgr->base_addr, KEYMGR_RESEED_INTERVAL_SHADOWED_REG_OFFSET, reg_val); | 
 |  | 
 |   return kDifOk; | 
 | } | 
 |  | 
 | dif_result_t dif_keymgr_advance_state(const dif_keymgr_t *keymgr, | 
 |                                       const dif_keymgr_state_params_t *params) { | 
 |   if (keymgr == NULL) { | 
 |     return kDifBadArg; | 
 |   } | 
 |  | 
 |   if (!is_ready(keymgr)) { | 
 |     return kDifLocked; | 
 |   } | 
 |  | 
 |   // Get current state and determine if we need to set the max key version and | 
 |   // sw binding value. | 
 |   max_key_version_reg_info_t max_key_ver_reg_info; | 
 |   uint32_t reg_working_state = | 
 |       mmio_region_read32(keymgr->base_addr, KEYMGR_WORKING_STATE_REG_OFFSET); | 
 |   if (!get_max_key_version_reg_info_for_next_state( | 
 |           (bitfield_field32_read(reg_working_state, | 
 |                                  KEYMGR_WORKING_STATE_STATE_FIELD)), | 
 |           &max_key_ver_reg_info)) { | 
 |     return kDifError; | 
 |   } | 
 |  | 
 |   // Set the binding value and max key version if keymgr is going to | 
 |   // transition to an operational state. | 
 |   if (max_key_ver_reg_info.is_required) { | 
 |     if (params == NULL) { | 
 |       return kDifBadArg; | 
 |     } | 
 |  | 
 |     // Check if SEALING_SW_BINDING_N registers are locked | 
 |     uint32_t reg_sw_binding_wen = mmio_region_read32( | 
 |         keymgr->base_addr, KEYMGR_SW_BINDING_REGWEN_REG_OFFSET); | 
 |     if (!bitfield_bit32_read(reg_sw_binding_wen, | 
 |                              KEYMGR_SW_BINDING_REGWEN_EN_BIT)) { | 
 |       return kDifLocked; | 
 |     } | 
 |  | 
 |     // Check if MAX_*_KEY_VER register is locked. | 
 |     uint32_t reg_max_key_ver_wen = mmio_region_read32( | 
 |         keymgr->base_addr, max_key_ver_reg_info.wen_reg_offset); | 
 |     if (!bitfield_bit32_read(reg_max_key_ver_wen, | 
 |                              max_key_ver_reg_info.wen_bit_index)) { | 
 |       return kDifLocked; | 
 |     } | 
 |  | 
 |     // Write and lock (rw0c) the software binding value. This register is | 
 |     // unlocked by hardware upon a successful state transition. | 
 |     mmio_region_memcpy_to_mmio32( | 
 |         keymgr->base_addr, KEYMGR_SEALING_SW_BINDING_0_REG_OFFSET, | 
 |         params->binding_value, sizeof(params->binding_value)); | 
 |     mmio_region_write32(keymgr->base_addr, KEYMGR_SW_BINDING_REGWEN_REG_OFFSET, | 
 |                         0); | 
 |  | 
 |     // Write and lock (rw0c) the max key version. | 
 |     mmio_region_write32_shadowed(keymgr->base_addr, | 
 |                                  max_key_ver_reg_info.reg_offset, | 
 |                                  params->max_key_version); | 
 |     mmio_region_write32(keymgr->base_addr, max_key_ver_reg_info.wen_reg_offset, | 
 |                         0); | 
 |   } else if (params != NULL) { | 
 |     return kDifBadArg; | 
 |   } | 
 |  | 
 |   // Advance state. | 
 |   start_operation(keymgr, | 
 |                   (start_operation_params_t){ | 
 |                       .dest = KEYMGR_CONTROL_SHADOWED_DEST_SEL_VALUE_NONE, | 
 |                       .op = KEYMGR_CONTROL_SHADOWED_OPERATION_VALUE_ADVANCE, | 
 |                   }); | 
 |  | 
 |   return kDifOk; | 
 | } | 
 |  | 
 | dif_result_t dif_keymgr_disable(const dif_keymgr_t *keymgr) { | 
 |   if (keymgr == NULL) { | 
 |     return kDifBadArg; | 
 |   } | 
 |  | 
 |   if (!is_ready(keymgr)) { | 
 |     return kDifLocked; | 
 |   } | 
 |  | 
 |   // Disable key manager. | 
 |   start_operation(keymgr, | 
 |                   (start_operation_params_t){ | 
 |                       .dest = KEYMGR_CONTROL_SHADOWED_DEST_SEL_VALUE_NONE, | 
 |                       .op = KEYMGR_CONTROL_SHADOWED_OPERATION_VALUE_DISABLE, | 
 |                   }); | 
 |  | 
 |   return kDifOk; | 
 | } | 
 |  | 
 | dif_result_t dif_keymgr_get_status_codes( | 
 |     const dif_keymgr_t *keymgr, dif_keymgr_status_codes_t *status_codes) { | 
 |   if (keymgr == NULL || status_codes == NULL) { | 
 |     return kDifBadArg; | 
 |   } | 
 |  | 
 |   // Read and clear OP_STATUS register (rw1c). | 
 |   uint32_t reg_op_status = | 
 |       mmio_region_read32(keymgr->base_addr, KEYMGR_OP_STATUS_REG_OFFSET); | 
 |   mmio_region_write32(keymgr->base_addr, KEYMGR_OP_STATUS_REG_OFFSET, | 
 |                       reg_op_status); | 
 |  | 
 |   bool is_idle = false; | 
 |   bool has_error = false; | 
 |   switch (reg_op_status) { | 
 |     case KEYMGR_OP_STATUS_STATUS_VALUE_IDLE: | 
 |       is_idle = true; | 
 |       break; | 
 |     case KEYMGR_OP_STATUS_STATUS_VALUE_DONE_SUCCESS: | 
 |       is_idle = true; | 
 |       break; | 
 |     case KEYMGR_OP_STATUS_STATUS_VALUE_DONE_ERROR: | 
 |       is_idle = true; | 
 |       has_error = true; | 
 |       break; | 
 |     case KEYMGR_OP_STATUS_STATUS_VALUE_WIP: | 
 |       break; | 
 |     default: | 
 |       return kDifError; | 
 |   } | 
 |  | 
 |   // Bit 0 of `dif_keymgr_status_codes_t` indicates whether the key manager is | 
 |   // idle or not. | 
 |   *status_codes = bitfield_bit32_write(0, 0, is_idle); | 
 |  | 
 |   if (has_error) { | 
 |     // Read and clear ERR_CODE register (rw1c). | 
 |     uint32_t reg_err_code = | 
 |         mmio_region_read32(keymgr->base_addr, KEYMGR_ERR_CODE_REG_OFFSET); | 
 |     mmio_region_write32(keymgr->base_addr, KEYMGR_ERR_CODE_REG_OFFSET, | 
 |                         reg_err_code); | 
 |     // Error bits start from bit 1 in `dif_keymgr_status_codes_t`. | 
 |     // Note: The mask is hardcoded since it is not auto generated yet. | 
 |     const bitfield_field32_t kErrorBitfield = (bitfield_field32_t){ | 
 |         .mask = 0xF, | 
 |         .index = 1, | 
 |     }; | 
 |     if (reg_err_code > kErrorBitfield.mask || reg_err_code == 0) { | 
 |       return kDifError; | 
 |     } | 
 |     *status_codes = | 
 |         bitfield_field32_write(*status_codes, kErrorBitfield, reg_err_code); | 
 |   } | 
 |  | 
 |   return kDifOk; | 
 | } | 
 |  | 
 | dif_result_t dif_keymgr_get_state(const dif_keymgr_t *keymgr, | 
 |                                   dif_keymgr_state_t *state) { | 
 |   if (keymgr == NULL || state == NULL) { | 
 |     return kDifBadArg; | 
 |   } | 
 |  | 
 |   uint32_t reg_state = | 
 |       mmio_region_read32(keymgr->base_addr, KEYMGR_WORKING_STATE_REG_OFFSET); | 
 |  | 
 |   switch (bitfield_field32_read(reg_state, KEYMGR_WORKING_STATE_STATE_FIELD)) { | 
 |     case KEYMGR_WORKING_STATE_STATE_VALUE_RESET: | 
 |       *state = kDifKeymgrStateReset; | 
 |       return kDifOk; | 
 |     case KEYMGR_WORKING_STATE_STATE_VALUE_INIT: | 
 |       *state = kDifKeymgrStateInitialized; | 
 |       return kDifOk; | 
 |     case KEYMGR_WORKING_STATE_STATE_VALUE_CREATOR_ROOT_KEY: | 
 |       *state = kDifKeymgrStateCreatorRootKey; | 
 |       return kDifOk; | 
 |     case KEYMGR_WORKING_STATE_STATE_VALUE_OWNER_INTERMEDIATE_KEY: | 
 |       *state = kDifKeymgrStateOwnerIntermediateKey; | 
 |       return kDifOk; | 
 |     case KEYMGR_WORKING_STATE_STATE_VALUE_OWNER_KEY: | 
 |       *state = kDifKeymgrStateOwnerRootKey; | 
 |       return kDifOk; | 
 |     case KEYMGR_WORKING_STATE_STATE_VALUE_DISABLED: | 
 |       *state = kDifKeymgrStateDisabled; | 
 |       return kDifOk; | 
 |     case KEYMGR_WORKING_STATE_STATE_VALUE_INVALID: | 
 |       *state = kDifKeymgrStateInvalid; | 
 |       return kDifOk; | 
 |     default: | 
 |       return kDifError; | 
 |   } | 
 | } | 
 |  | 
 | dif_result_t dif_keymgr_generate_identity_seed(const dif_keymgr_t *keymgr) { | 
 |   if (keymgr == NULL) { | 
 |     return kDifBadArg; | 
 |   } | 
 |  | 
 |   if (!is_ready(keymgr)) { | 
 |     return kDifLocked; | 
 |   } | 
 |  | 
 |   start_operation(keymgr, | 
 |                   (start_operation_params_t){ | 
 |                       .dest = KEYMGR_CONTROL_SHADOWED_DEST_SEL_VALUE_NONE, | 
 |                       .op = KEYMGR_CONTROL_SHADOWED_OPERATION_VALUE_GENERATE_ID, | 
 |                   }); | 
 |  | 
 |   return kDifOk; | 
 | } | 
 |  | 
 | dif_result_t dif_keymgr_generate_versioned_key( | 
 |     const dif_keymgr_t *keymgr, dif_keymgr_versioned_key_params_t params) { | 
 |   if (keymgr == NULL) { | 
 |     return kDifBadArg; | 
 |   } | 
 |  | 
 |   start_operation_params_t hw_op_params; | 
 |   switch (params.dest) { | 
 |     case kDifKeymgrVersionedKeyDestSw: | 
 |       hw_op_params = (start_operation_params_t){ | 
 |           .dest = KEYMGR_CONTROL_SHADOWED_DEST_SEL_VALUE_NONE, | 
 |           .op = KEYMGR_CONTROL_SHADOWED_OPERATION_VALUE_GENERATE_SW_OUTPUT, | 
 |       }; | 
 |       break; | 
 |     case kDifKeymgrVersionedKeyDestAes: | 
 |       hw_op_params = (start_operation_params_t){ | 
 |           .dest = KEYMGR_CONTROL_SHADOWED_DEST_SEL_VALUE_AES, | 
 |           .op = KEYMGR_CONTROL_SHADOWED_OPERATION_VALUE_GENERATE_HW_OUTPUT, | 
 |       }; | 
 |       break; | 
 |     case kDifKeymgrVersionedKeyDestKmac: | 
 |       hw_op_params = (start_operation_params_t){ | 
 |           .dest = KEYMGR_CONTROL_SHADOWED_DEST_SEL_VALUE_KMAC, | 
 |           .op = KEYMGR_CONTROL_SHADOWED_OPERATION_VALUE_GENERATE_HW_OUTPUT, | 
 |       }; | 
 |       break; | 
 |     case kDifKeymgrVersionedKeyDestOtbn: | 
 |       hw_op_params = (start_operation_params_t){ | 
 |           .dest = KEYMGR_CONTROL_SHADOWED_DEST_SEL_VALUE_OTBN, | 
 |           .op = KEYMGR_CONTROL_SHADOWED_OPERATION_VALUE_GENERATE_HW_OUTPUT, | 
 |       }; | 
 |       break; | 
 |     default: | 
 |       return kDifBadArg; | 
 |   } | 
 |  | 
 |   if (!is_ready(keymgr)) { | 
 |     return kDifLocked; | 
 |   } | 
 |  | 
 |   // Set salt and version | 
 |   mmio_region_memcpy_to_mmio32(keymgr->base_addr, KEYMGR_SALT_0_REG_OFFSET, | 
 |                                params.salt, sizeof(params.salt)); | 
 |   mmio_region_write32(keymgr->base_addr, KEYMGR_KEY_VERSION_REG_OFFSET, | 
 |                       params.version); | 
 |  | 
 |   start_operation(keymgr, hw_op_params); | 
 |  | 
 |   return kDifOk; | 
 | } | 
 |  | 
 | dif_result_t dif_keymgr_sideload_clear_set_enabled(const dif_keymgr_t *keymgr, | 
 |                                                    dif_toggle_t state) { | 
 |   if (keymgr == NULL || !dif_is_valid_toggle(state)) { | 
 |     return kDifBadArg; | 
 |   } | 
 |  | 
 |   dif_keymgr_sideload_clr_t val = state == kDifToggleEnabled | 
 |                                       ? kDifKeyMgrSideLoadClearAll | 
 |                                       : kDifKeyMgrSideLoadClearNone; | 
 |  | 
 |   mmio_region_write32(keymgr->base_addr, KEYMGR_SIDELOAD_CLEAR_REG_OFFSET, val); | 
 |  | 
 |   return kDifOk; | 
 | } | 
 |  | 
 | dif_result_t dif_keymgr_sideload_clear_get_enabled(const dif_keymgr_t *keymgr, | 
 |                                                    dif_toggle_t *state) { | 
 |   if (keymgr == NULL || state == NULL) { | 
 |     return kDifBadArg; | 
 |   } | 
 |  | 
 |   uint32_t reg_val = | 
 |       mmio_region_read32(keymgr->base_addr, KEYMGR_SIDELOAD_CLEAR_REG_OFFSET); | 
 |   *state = dif_bool_to_toggle(reg_val == kDifKeyMgrSideLoadClearAll); | 
 |  | 
 |   return kDifOk; | 
 | } | 
 |  | 
 | dif_result_t dif_keymgr_read_output(const dif_keymgr_t *keymgr, | 
 |                                     dif_keymgr_output_t *output) { | 
 |   if (keymgr == NULL || output == NULL) { | 
 |     return kDifBadArg; | 
 |   } | 
 |  | 
 |   mmio_region_memcpy_from_mmio32(keymgr->base_addr, | 
 |                                  KEYMGR_SW_SHARE0_OUTPUT_0_REG_OFFSET, | 
 |                                  output->value[0], sizeof(output->value[0])); | 
 |   mmio_region_memcpy_from_mmio32(keymgr->base_addr, | 
 |                                  KEYMGR_SW_SHARE1_OUTPUT_0_REG_OFFSET, | 
 |                                  output->value[1], sizeof(output->value[1])); | 
 |  | 
 |   return kDifOk; | 
 | } |