|  | // 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."); | 
|  | // TODO: Uncomment when lowRISC/opentitan#5194 is completed. | 
|  | // TODO: Consider defining a macro once all assertions are enabled. | 
|  | // 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."); | 
|  | // TODO: Uncomment when lowRISC/opentitan#5194 is completed. | 
|  | // 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_DEST_SEL_FIELD, params.dest); | 
|  | reg_control = bitfield_field32_write( | 
|  | reg_control, KEYMGR_CONTROL_OPERATION_FIELD, params.op); | 
|  | reg_control = | 
|  | bitfield_bit32_write(reg_control, KEYMGR_CONTROL_START_BIT, true); | 
|  | mmio_region_write32(keymgr->base_addr, KEYMGR_CONTROL_REG_OFFSET, | 
|  | reg_control); | 
|  | } | 
|  |  | 
|  | 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_DEST_SEL_VALUE_NONE, | 
|  | .op = KEYMGR_CONTROL_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_DEST_SEL_VALUE_NONE, | 
|  | .op = KEYMGR_CONTROL_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_DEST_SEL_VALUE_NONE, | 
|  | .op = KEYMGR_CONTROL_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_DEST_SEL_VALUE_NONE, | 
|  | .op = KEYMGR_CONTROL_OPERATION_VALUE_GENERATE_SW_OUTPUT, | 
|  | }; | 
|  | break; | 
|  | case kDifKeymgrVersionedKeyDestAes: | 
|  | hw_op_params = (start_operation_params_t){ | 
|  | .dest = KEYMGR_CONTROL_DEST_SEL_VALUE_AES, | 
|  | .op = KEYMGR_CONTROL_OPERATION_VALUE_GENERATE_HW_OUTPUT, | 
|  | }; | 
|  | break; | 
|  | case kDifKeymgrVersionedKeyDestKmac: | 
|  | hw_op_params = (start_operation_params_t){ | 
|  | .dest = KEYMGR_CONTROL_DEST_SEL_VALUE_KMAC, | 
|  | .op = KEYMGR_CONTROL_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; | 
|  | } |