| // 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_sram_ctrl.h" |
| |
| #include "sw/device/lib/base/multibits.h" |
| |
| #include "sram_ctrl_regs.h" // Generated. |
| |
| /** |
| * Obtains the lock state of the "Control" register. |
| * |
| * When locked, new scrambling key and SRAM pseudo-random data overwriting |
| * requests are not available. |
| */ |
| static bool sram_ctrl_locked_ctrl(const dif_sram_ctrl_t *sram_ctrl) { |
| return mmio_region_read32(sram_ctrl->base_addr, |
| SRAM_CTRL_CTRL_REGWEN_REG_OFFSET) |
| ? false |
| : true; |
| } |
| |
| /** |
| * Obtains the lock state of the "Exec enable" register. |
| * |
| * When locked, execution from SRAM is disabled, and an attempt to do so |
| * will result in an access violation. |
| */ |
| static bool sram_ctrl_exec_locked(const dif_sram_ctrl_t *sram_ctrl) { |
| return mmio_region_read32(sram_ctrl->base_addr, |
| SRAM_CTRL_EXEC_REGWEN_REG_OFFSET) |
| ? false |
| : true; |
| } |
| |
| /** |
| * Locks SRAM Controller "Control" functionality. |
| * |
| * SRAM Scrambling and RAM wiping is no longer available. |
| */ |
| static void sram_ctrl_lock_ctrl(const dif_sram_ctrl_t *sram_ctrl) { |
| mmio_region_write32(sram_ctrl->base_addr, SRAM_CTRL_CTRL_REGWEN_REG_OFFSET, |
| 0); |
| } |
| |
| /** |
| * Locks SRAM Controller "Execute" functionality. |
| * |
| * Execution from SRAM cannot be changed (when enabled - it stays enabled, and |
| * vice versa). |
| */ |
| static void sram_ctrl_lock_exec(const dif_sram_ctrl_t *sram_ctrl) { |
| mmio_region_write32(sram_ctrl->base_addr, SRAM_CTRL_EXEC_REGWEN_REG_OFFSET, |
| 0); |
| } |
| |
| /** |
| * Obtains the SRAM Controller statues. |
| * |
| * `dif_sram_ctrl_status_t` can be used to query individual flags. |
| */ |
| static uint32_t sram_ctrl_get_status(const dif_sram_ctrl_t *sram_ctrl) { |
| return mmio_region_read32(sram_ctrl->base_addr, SRAM_CTRL_STATUS_REG_OFFSET); |
| } |
| |
| dif_result_t dif_sram_ctrl_scramble(const dif_sram_ctrl_t *sram_ctrl) { |
| if (sram_ctrl == NULL) { |
| return kDifBadArg; |
| } |
| |
| if (sram_ctrl_locked_ctrl(sram_ctrl)) { |
| return kDifLocked; |
| } |
| |
| // Issue request for new scrambling key. |
| uint32_t reg = |
| bitfield_bit32_write(0, SRAM_CTRL_CTRL_RENEW_SCR_KEY_BIT, true); |
| mmio_region_write32(sram_ctrl->base_addr, SRAM_CTRL_CTRL_REG_OFFSET, reg); |
| |
| // Wait until the scrambling key has been updated. |
| dif_sram_ctrl_status_bitfield_t status; |
| do { |
| status = sram_ctrl_get_status(sram_ctrl); |
| } while ((status & kDifSramCtrlStatusScrKeyValid) == 0); |
| |
| // Overwrite memory with pseudo random data. |
| reg = bitfield_bit32_write(0, SRAM_CTRL_CTRL_INIT_BIT, true); |
| mmio_region_write32(sram_ctrl->base_addr, SRAM_CTRL_CTRL_REG_OFFSET, reg); |
| |
| // Wait for memory to be overwritten with pseudo random data. |
| do { |
| status = sram_ctrl_get_status(sram_ctrl); |
| } while ((status & kDifSramCtrlStatusInitDone) == 0); |
| |
| // Check for the errors during memory overwriting. |
| return (status & kDifSramCtrlStatusInitErr) == 0 ? kDifOk : kDifError; |
| } |
| |
| dif_result_t dif_sram_ctrl_request_new_key(const dif_sram_ctrl_t *sram_ctrl) { |
| if (sram_ctrl == NULL) { |
| return kDifBadArg; |
| } |
| |
| if (sram_ctrl_locked_ctrl(sram_ctrl)) { |
| return kDifLocked; |
| } |
| |
| uint32_t reg = |
| bitfield_bit32_write(0, SRAM_CTRL_CTRL_RENEW_SCR_KEY_BIT, true); |
| mmio_region_write32(sram_ctrl->base_addr, SRAM_CTRL_CTRL_REG_OFFSET, reg); |
| |
| return kDifOk; |
| } |
| |
| dif_result_t dif_sram_ctrl_wipe(const dif_sram_ctrl_t *sram_ctrl) { |
| if (sram_ctrl == NULL) { |
| return kDifBadArg; |
| } |
| |
| if (sram_ctrl_locked_ctrl(sram_ctrl)) { |
| return kDifLocked; |
| } |
| |
| uint32_t reg = bitfield_bit32_write(0, SRAM_CTRL_CTRL_INIT_BIT, true); |
| mmio_region_write32(sram_ctrl->base_addr, SRAM_CTRL_CTRL_REG_OFFSET, reg); |
| |
| return kDifOk; |
| } |
| |
| dif_result_t dif_sram_ctrl_get_status(const dif_sram_ctrl_t *sram_ctrl, |
| dif_sram_ctrl_status_bitfield_t *status) { |
| if (sram_ctrl == NULL) { |
| return kDifBadArg; |
| } |
| |
| if (status == NULL) { |
| return kDifBadArg; |
| } |
| |
| *status = sram_ctrl_get_status(sram_ctrl); |
| |
| return kDifOk; |
| } |
| |
| dif_result_t dif_sram_ctrl_exec_get_enabled(const dif_sram_ctrl_t *sram_ctrl, |
| dif_toggle_t *state) { |
| if (sram_ctrl == NULL || state == NULL) { |
| return kDifBadArg; |
| } |
| |
| uint32_t reg = |
| mmio_region_read32(sram_ctrl->base_addr, SRAM_CTRL_EXEC_REG_OFFSET); |
| |
| *state = (reg == kMultiBitBool4True) ? kDifToggleEnabled : kDifToggleDisabled; |
| |
| return kDifOk; |
| } |
| |
| dif_result_t dif_sram_ctrl_exec_set_enabled(const dif_sram_ctrl_t *sram_ctrl, |
| dif_toggle_t state) { |
| if (sram_ctrl == NULL) { |
| return kDifBadArg; |
| } |
| |
| if (sram_ctrl_exec_locked(sram_ctrl)) { |
| return kDifLocked; |
| } |
| |
| uint32_t value = |
| (state == kDifToggleEnabled) ? kMultiBitBool4True : kMultiBitBool4False; |
| mmio_region_write32(sram_ctrl->base_addr, SRAM_CTRL_EXEC_REG_OFFSET, value); |
| |
| return kDifOk; |
| } |
| |
| dif_result_t dif_sram_ctrl_lock(const dif_sram_ctrl_t *sram_ctrl, |
| dif_sram_ctrl_lock_t lock) { |
| if (sram_ctrl == NULL) { |
| return kDifBadArg; |
| } |
| |
| switch (lock) { |
| case kDifSramCtrlLockCtrl: |
| sram_ctrl_lock_ctrl(sram_ctrl); |
| break; |
| case kDifSramCtrlLockExec: |
| sram_ctrl_lock_exec(sram_ctrl); |
| break; |
| default: |
| return kDifError; |
| } |
| |
| return kDifOk; |
| } |
| |
| dif_result_t dif_sram_ctrl_is_locked(const dif_sram_ctrl_t *sram_ctrl, |
| dif_sram_ctrl_lock_t lock, |
| bool *is_locked) { |
| if (sram_ctrl == NULL || is_locked == NULL) { |
| return kDifBadArg; |
| } |
| |
| switch (lock) { |
| case kDifSramCtrlLockCtrl: |
| *is_locked = sram_ctrl_locked_ctrl(sram_ctrl); |
| break; |
| case kDifSramCtrlLockExec: |
| *is_locked = sram_ctrl_exec_locked(sram_ctrl); |
| break; |
| default: |
| return kDifError; |
| } |
| |
| return kDifOk; |
| } |