| // 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 "keymgr_regs.h" // Generated. |
| |
| /** |
| * 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. |
| */ |
| DIF_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->params.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->params.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. |
| */ |
| DIF_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->params.base_addr, KEYMGR_CONTROL_REG_OFFSET, |
| reg_control); |
| } |
| |
| /** |
| * Returns the bit index for a given IRQ. |
| */ |
| DIF_WARN_UNUSED_RESULT |
| static bool get_irq_bit_index(dif_keymgr_irq_t irq, |
| bitfield_bit32_index_t *bit_index) { |
| switch (irq) { |
| case kDifKeymgrIrqDone: |
| *bit_index = KEYMGR_INTR_COMMON_OP_DONE_BIT; |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| /** |
| * Checks if a value is a valid `dif_keymgr_toggle_t` and converts it to `bool`. |
| */ |
| DIF_WARN_UNUSED_RESULT |
| static bool toggle_to_bool(dif_keymgr_toggle_t val, bool *val_bool) { |
| switch (val) { |
| case kDifKeymgrToggleEnabled: |
| *val_bool = true; |
| break; |
| case kDifKeymgrToggleDisabled: |
| *val_bool = false; |
| break; |
| default: |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * Converts a `bool` to `dif_keymgr_toggle_t`. |
| */ |
| static dif_keymgr_toggle_t bool_to_toggle(bool val) { |
| return val ? kDifKeymgrToggleEnabled : kDifKeymgrToggleDisabled; |
| } |
| |
| dif_keymgr_result_t dif_keymgr_init(dif_keymgr_params_t params, |
| dif_keymgr_t *keymgr) { |
| if (keymgr == NULL) { |
| return kDifKeymgrBadArg; |
| } |
| |
| *keymgr = (dif_keymgr_t){.params = params}; |
| |
| return kDifKeymgrOk; |
| } |
| |
| dif_keymgr_result_t dif_keymgr_configure(const dif_keymgr_t *keymgr, |
| dif_keymgr_config_t config) { |
| if (keymgr == NULL) { |
| return kDifKeymgrBadArg; |
| } |
| |
| uint32_t reg_val = |
| bitfield_field32_write(0, KEYMGR_RESEED_INTERVAL_SHADOWED_VAL_FIELD, |
| config.entropy_reseed_interval); |
| mmio_region_write32_shadowed(keymgr->params.base_addr, |
| KEYMGR_RESEED_INTERVAL_SHADOWED_REG_OFFSET, |
| reg_val); |
| |
| return kDifKeymgrOk; |
| } |
| |
| dif_keymgr_lockable_result_t dif_keymgr_advance_state( |
| const dif_keymgr_t *keymgr, const dif_keymgr_state_params_t *params) { |
| if (keymgr == NULL) { |
| return kDifKeymgrLockableBadArg; |
| } |
| |
| if (!is_ready(keymgr)) { |
| return kDifKeymgrLockableLocked; |
| } |
| |
| // 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->params.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 kDifKeymgrLockableError; |
| } |
| |
| // 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 kDifKeymgrLockableBadArg; |
| } |
| |
| // Check if SEALING_SW_BINDING_N registers are locked |
| uint32_t reg_sw_binding_wen = mmio_region_read32( |
| keymgr->params.base_addr, KEYMGR_SW_BINDING_REGWEN_REG_OFFSET); |
| if (!bitfield_bit32_read(reg_sw_binding_wen, |
| KEYMGR_SW_BINDING_REGWEN_EN_BIT)) { |
| return kDifKeymgrLockableLocked; |
| } |
| |
| // Check if MAX_*_KEY_VER register is locked. |
| uint32_t reg_max_key_ver_wen = mmio_region_read32( |
| keymgr->params.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 kDifKeymgrLockableLocked; |
| } |
| |
| // 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->params.base_addr, KEYMGR_SEALING_SW_BINDING_0_REG_OFFSET, |
| params->binding_value, sizeof(params->binding_value)); |
| mmio_region_write32(keymgr->params.base_addr, |
| KEYMGR_SW_BINDING_REGWEN_REG_OFFSET, 0); |
| |
| // Write and lock (rw0c) the max key version. |
| mmio_region_write32_shadowed(keymgr->params.base_addr, |
| max_key_ver_reg_info.reg_offset, |
| params->max_key_version); |
| mmio_region_write32(keymgr->params.base_addr, |
| max_key_ver_reg_info.wen_reg_offset, 0); |
| } else if (params != NULL) { |
| return kDifKeymgrLockableBadArg; |
| } |
| |
| // Advance state. |
| start_operation(keymgr, (start_operation_params_t){ |
| .dest = KEYMGR_CONTROL_DEST_SEL_VALUE_NONE, |
| .op = KEYMGR_CONTROL_OPERATION_VALUE_ADVANCE, |
| }); |
| |
| return kDifKeymgrLockableOk; |
| } |
| |
| dif_keymgr_lockable_result_t dif_keymgr_disable(const dif_keymgr_t *keymgr) { |
| if (keymgr == NULL) { |
| return kDifKeymgrLockableBadArg; |
| } |
| |
| if (!is_ready(keymgr)) { |
| return kDifKeymgrLockableLocked; |
| } |
| |
| // Disable key manager. |
| start_operation(keymgr, (start_operation_params_t){ |
| .dest = KEYMGR_CONTROL_DEST_SEL_VALUE_NONE, |
| .op = KEYMGR_CONTROL_OPERATION_VALUE_DISABLE, |
| }); |
| |
| return kDifKeymgrLockableOk; |
| } |
| |
| dif_keymgr_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 kDifKeymgrBadArg; |
| } |
| |
| // Read and clear OP_STATUS register (rw1c). |
| uint32_t reg_op_status = |
| mmio_region_read32(keymgr->params.base_addr, KEYMGR_OP_STATUS_REG_OFFSET); |
| mmio_region_write32(keymgr->params.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 kDifKeymgrError; |
| } |
| |
| // 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->params.base_addr, |
| KEYMGR_ERR_CODE_REG_OFFSET); |
| mmio_region_write32(keymgr->params.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 kDifKeymgrError; |
| } |
| *status_codes = |
| bitfield_field32_write(*status_codes, kErrorBitfield, reg_err_code); |
| } |
| |
| return kDifKeymgrOk; |
| } |
| |
| dif_keymgr_result_t dif_keymgr_get_state(const dif_keymgr_t *keymgr, |
| dif_keymgr_state_t *state) { |
| if (keymgr == NULL || state == NULL) { |
| return kDifKeymgrBadArg; |
| } |
| |
| uint32_t reg_state = mmio_region_read32(keymgr->params.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 kDifKeymgrOk; |
| case KEYMGR_WORKING_STATE_STATE_VALUE_INIT: |
| *state = kDifKeymgrStateInitialized; |
| return kDifKeymgrOk; |
| case KEYMGR_WORKING_STATE_STATE_VALUE_CREATOR_ROOT_KEY: |
| *state = kDifKeymgrStateCreatorRootKey; |
| return kDifKeymgrOk; |
| case KEYMGR_WORKING_STATE_STATE_VALUE_OWNER_INTERMEDIATE_KEY: |
| *state = kDifKeymgrStateOwnerIntermediateKey; |
| return kDifKeymgrOk; |
| case KEYMGR_WORKING_STATE_STATE_VALUE_OWNER_KEY: |
| *state = kDifKeymgrStateOwnerRootKey; |
| return kDifKeymgrOk; |
| case KEYMGR_WORKING_STATE_STATE_VALUE_DISABLED: |
| *state = kDifKeymgrStateDisabled; |
| return kDifKeymgrOk; |
| case KEYMGR_WORKING_STATE_STATE_VALUE_INVALID: |
| *state = kDifKeymgrStateInvalid; |
| return kDifKeymgrOk; |
| default: |
| return kDifKeymgrError; |
| } |
| } |
| |
| dif_keymgr_lockable_result_t dif_keymgr_generate_identity_seed( |
| const dif_keymgr_t *keymgr) { |
| if (keymgr == NULL) { |
| return kDifKeymgrLockableBadArg; |
| } |
| |
| if (!is_ready(keymgr)) { |
| return kDifKeymgrLockableLocked; |
| } |
| |
| start_operation(keymgr, (start_operation_params_t){ |
| .dest = KEYMGR_CONTROL_DEST_SEL_VALUE_NONE, |
| .op = KEYMGR_CONTROL_OPERATION_VALUE_GENERATE_ID, |
| }); |
| |
| return kDifKeymgrLockableOk; |
| } |
| |
| dif_keymgr_lockable_result_t dif_keymgr_generate_versioned_key( |
| const dif_keymgr_t *keymgr, dif_keymgr_versioned_key_params_t params) { |
| if (keymgr == NULL) { |
| return kDifKeymgrLockableBadArg; |
| } |
| |
| 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 kDifKeymgrLockableBadArg; |
| } |
| |
| if (!is_ready(keymgr)) { |
| return kDifKeymgrLockableLocked; |
| } |
| |
| // Set salt and version |
| mmio_region_memcpy_to_mmio32(keymgr->params.base_addr, |
| KEYMGR_SALT_0_REG_OFFSET, params.salt, |
| sizeof(params.salt)); |
| mmio_region_write32(keymgr->params.base_addr, KEYMGR_KEY_VERSION_REG_OFFSET, |
| params.version); |
| |
| start_operation(keymgr, hw_op_params); |
| |
| return kDifKeymgrLockableOk; |
| } |
| |
| dif_keymgr_result_t dif_keymgr_sideload_clear_set_enabled( |
| const dif_keymgr_t *keymgr, dif_keymgr_toggle_t state) { |
| bool enable = false; |
| if (keymgr == NULL || !toggle_to_bool(state, &enable)) { |
| return kDifKeymgrBadArg; |
| } |
| |
| dif_keymgr_sideload_clr_t val = state == kDifKeymgrToggleEnabled |
| ? kDifKeyMgrSideLoadClearAll |
| : kDifKeyMgrSideLoadClearNone; |
| |
| mmio_region_write32(keymgr->params.base_addr, |
| KEYMGR_SIDELOAD_CLEAR_REG_OFFSET, val); |
| |
| return kDifKeymgrOk; |
| } |
| |
| dif_keymgr_result_t dif_keymgr_sideload_clear_get_enabled( |
| const dif_keymgr_t *keymgr, dif_keymgr_toggle_t *state) { |
| if (keymgr == NULL || state == NULL) { |
| return kDifKeymgrBadArg; |
| } |
| |
| uint32_t reg_val = mmio_region_read32(keymgr->params.base_addr, |
| KEYMGR_SIDELOAD_CLEAR_REG_OFFSET); |
| *state = bool_to_toggle(reg_val == kDifKeyMgrSideLoadClearAll); |
| |
| return kDifKeymgrOk; |
| } |
| |
| dif_keymgr_result_t dif_keymgr_read_output(const dif_keymgr_t *keymgr, |
| dif_keymgr_output_t *output) { |
| if (keymgr == NULL || output == NULL) { |
| return kDifKeymgrBadArg; |
| } |
| |
| mmio_region_memcpy_from_mmio32(keymgr->params.base_addr, |
| KEYMGR_SW_SHARE0_OUTPUT_0_REG_OFFSET, |
| output->value[0], sizeof(output->value[0])); |
| mmio_region_memcpy_from_mmio32(keymgr->params.base_addr, |
| KEYMGR_SW_SHARE1_OUTPUT_0_REG_OFFSET, |
| output->value[1], sizeof(output->value[1])); |
| |
| return kDifKeymgrOk; |
| } |
| |
| dif_keymgr_result_t dif_keymgr_alert_force(const dif_keymgr_t *keymgr, |
| dif_keymgr_alert_t alert) { |
| if (keymgr == NULL) { |
| return kDifKeymgrBadArg; |
| } |
| |
| bitfield_bit32_index_t bit_index; |
| switch (alert) { |
| case kDifKeymgrAlertHardware: |
| bit_index = KEYMGR_ALERT_TEST_FATAL_FAULT_ERR_BIT; |
| break; |
| case kDifKeymgrAlertSoftware: |
| bit_index = KEYMGR_ALERT_TEST_RECOV_OPERATION_ERR_BIT; |
| break; |
| default: |
| return kDifKeymgrBadArg; |
| } |
| |
| mmio_region_write32(keymgr->params.base_addr, KEYMGR_ALERT_TEST_REG_OFFSET, |
| bitfield_bit32_write(0, bit_index, true)); |
| |
| return kDifKeymgrOk; |
| } |
| |
| dif_keymgr_result_t dif_keymgr_irq_is_pending(const dif_keymgr_t *keymgr, |
| dif_keymgr_irq_t irq, |
| bool *is_pending) { |
| bitfield_bit32_index_t bit_index; |
| if (keymgr == NULL || !get_irq_bit_index(irq, &bit_index) || |
| is_pending == NULL) { |
| return kDifKeymgrBadArg; |
| } |
| |
| uint32_t reg_val = mmio_region_read32(keymgr->params.base_addr, |
| KEYMGR_INTR_STATE_REG_OFFSET); |
| *is_pending = bitfield_bit32_read(reg_val, bit_index); |
| |
| return kDifKeymgrOk; |
| } |
| |
| dif_keymgr_result_t dif_keymgr_irq_acknowledge(const dif_keymgr_t *keymgr, |
| dif_keymgr_irq_t irq) { |
| bitfield_bit32_index_t bit_index; |
| if (keymgr == NULL || !get_irq_bit_index(irq, &bit_index)) { |
| return kDifKeymgrBadArg; |
| } |
| |
| uint32_t reg_val = bitfield_bit32_write(0, bit_index, true); |
| mmio_region_write32(keymgr->params.base_addr, KEYMGR_INTR_STATE_REG_OFFSET, |
| reg_val); |
| |
| return kDifKeymgrOk; |
| } |
| |
| dif_keymgr_result_t dif_keymgr_irq_get_enabled(const dif_keymgr_t *keymgr, |
| dif_keymgr_irq_t irq, |
| dif_keymgr_toggle_t *state) { |
| bitfield_bit32_index_t bit_index; |
| if (keymgr == NULL || !get_irq_bit_index(irq, &bit_index) || state == NULL) { |
| return kDifKeymgrBadArg; |
| } |
| |
| uint32_t reg_val = mmio_region_read32(keymgr->params.base_addr, |
| KEYMGR_INTR_ENABLE_REG_OFFSET); |
| *state = bool_to_toggle(bitfield_bit32_read(reg_val, bit_index)); |
| |
| return kDifKeymgrOk; |
| } |
| |
| dif_keymgr_result_t dif_keymgr_irq_set_enabled(const dif_keymgr_t *keymgr, |
| dif_keymgr_irq_t irq, |
| dif_keymgr_toggle_t state) { |
| bitfield_bit32_index_t bit_index; |
| bool enable = false; |
| if (keymgr == NULL || !get_irq_bit_index(irq, &bit_index) || |
| !toggle_to_bool(state, &enable)) { |
| return kDifKeymgrBadArg; |
| } |
| |
| uint32_t reg_val = mmio_region_read32(keymgr->params.base_addr, |
| KEYMGR_INTR_ENABLE_REG_OFFSET); |
| reg_val = bitfield_bit32_write(reg_val, bit_index, enable); |
| mmio_region_write32(keymgr->params.base_addr, KEYMGR_INTR_ENABLE_REG_OFFSET, |
| reg_val); |
| |
| return kDifKeymgrOk; |
| } |
| |
| dif_keymgr_result_t dif_keymgr_irq_force(const dif_keymgr_t *keymgr, |
| dif_keymgr_irq_t irq) { |
| bitfield_bit32_index_t bit_index; |
| if (keymgr == NULL || !get_irq_bit_index(irq, &bit_index)) { |
| return kDifKeymgrBadArg; |
| } |
| |
| uint32_t reg_val = bitfield_bit32_write(0, bit_index, true); |
| mmio_region_write32(keymgr->params.base_addr, KEYMGR_INTR_TEST_REG_OFFSET, |
| reg_val); |
| |
| return kDifKeymgrOk; |
| } |
| |
| dif_keymgr_result_t dif_keymgr_irq_disable_all( |
| const dif_keymgr_t *keymgr, dif_keymgr_irq_snapshot_t *snapshot) { |
| if (keymgr == NULL) { |
| return kDifKeymgrBadArg; |
| } |
| |
| if (snapshot != NULL) { |
| *snapshot = mmio_region_read32(keymgr->params.base_addr, |
| KEYMGR_INTR_ENABLE_REG_OFFSET); |
| } |
| mmio_region_write32(keymgr->params.base_addr, KEYMGR_INTR_ENABLE_REG_OFFSET, |
| 0); |
| |
| return kDifKeymgrOk; |
| } |
| |
| dif_keymgr_result_t dif_keymgr_irq_restore_all( |
| const dif_keymgr_t *keymgr, const dif_keymgr_irq_snapshot_t *snapshot) { |
| if (keymgr == NULL || snapshot == NULL) { |
| return kDifKeymgrBadArg; |
| } |
| |
| mmio_region_write32(keymgr->params.base_addr, KEYMGR_INTR_ENABLE_REG_OFFSET, |
| *snapshot); |
| |
| return kDifKeymgrOk; |
| } |