| // 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" |
| |
| /** |
| * Make sure dif_keymgr_sideload_clr_t enum is in sync with autogenarated |
| * values. |
| */ |
| OT_ASSERT_ENUM_VALUE(kDifKeyMgrSideLoadClearNone, |
| KEYMGR_SIDELOAD_CLEAR_VAL_VALUE_NONE); |
| OT_ASSERT_ENUM_VALUE(kDifKeyMgrSideLoadClearAes, |
| KEYMGR_SIDELOAD_CLEAR_VAL_VALUE_AES); |
| OT_ASSERT_ENUM_VALUE(kDifKeyMgrSideLoadClearKmac, |
| KEYMGR_SIDELOAD_CLEAR_VAL_VALUE_KMAC); |
| OT_ASSERT_ENUM_VALUE(kDifKeyMgrSideLoadClearOtbn, |
| KEYMGR_SIDELOAD_CLEAR_VAL_VALUE_OTBN); |
| OT_ASSERT_ENUM_VALUE(kDifKeyMgrSideLoadClearAll, |
| KEYMGR_SIDELOAD_CLEAR_VAL_MASK); |
| |
| /** |
| * 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_advance_state_raw(const dif_keymgr_t *keymgr) { |
| if (keymgr == NULL) { |
| return kDifBadArg; |
| } |
| |
| if (!is_ready(keymgr)) { |
| return kDifLocked; |
| } |
| |
| // 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); |
| |
| 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; |
| mmio_region_write32(keymgr->base_addr, KEYMGR_OP_STATUS_REG_OFFSET, |
| reg_op_status); |
| break; |
| case KEYMGR_OP_STATUS_STATUS_VALUE_DONE_ERROR: |
| is_idle = true; |
| has_error = true; |
| mmio_region_write32(keymgr->base_addr, KEYMGR_OP_STATUS_REG_OFFSET, |
| reg_op_status); |
| 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; |
| } |
| |
| dif_result_t dif_keymgr_read_binding(const dif_keymgr_t *keymgr, |
| dif_keymgr_binding_value_t *output) { |
| if (keymgr == NULL || output == NULL) { |
| return kDifBadArg; |
| } |
| |
| mmio_region_memcpy_from_mmio32(keymgr->base_addr, |
| KEYMGR_SEALING_SW_BINDING_0_REG_OFFSET, |
| output->sealing, sizeof(output->sealing)); |
| |
| mmio_region_memcpy_from_mmio32( |
| keymgr->base_addr, KEYMGR_ATTEST_SW_BINDING_0_REG_OFFSET, |
| output->attestation, sizeof(output->attestation)); |
| |
| return kDifOk; |
| } |
| |
| dif_result_t dif_keymgr_read_max_key_version( |
| const dif_keymgr_t *keymgr, dif_keymgr_max_key_version_t *versions) { |
| if (keymgr == NULL || versions == NULL) { |
| return kDifBadArg; |
| } |
| |
| versions->creator_max_key_version = mmio_region_read32( |
| keymgr->base_addr, KEYMGR_MAX_CREATOR_KEY_VER_SHADOWED_REG_OFFSET); |
| versions->owner_int_max_key_version = mmio_region_read32( |
| keymgr->base_addr, KEYMGR_MAX_OWNER_INT_KEY_VER_SHADOWED_REG_OFFSET); |
| versions->owner_max_key_version = mmio_region_read32( |
| keymgr->base_addr, KEYMGR_MAX_OWNER_KEY_VER_SHADOWED_REG_OFFSET); |
| |
| return kDifOk; |
| } |