| // 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/testing/sram_ctrl_testutils.h" |
| |
| #include "sw/device/lib/base/mmio.h" |
| #include "sw/device/lib/dif/dif_sram_ctrl.h" |
| #include "sw/device/lib/runtime/ibex.h" |
| #include "sw/device/lib/runtime/log.h" |
| #include "sw/device/lib/testing/test_framework/check.h" |
| |
| void sram_ctrl_testutils_write(uintptr_t address, |
| const sram_ctrl_testutils_data_t data) { |
| mmio_region_t region = mmio_region_from_addr(address); |
| for (size_t index = 0; index < data.len; ++index) { |
| mmio_region_write32(region, sizeof(uint32_t) * index, data.words[index]); |
| } |
| } |
| |
| /** |
| * Checks whether the SRAM scramble operation has finished. |
| */ |
| static bool scramble_finished(const dif_sram_ctrl_t *sram_ctrl) { |
| dif_sram_ctrl_status_bitfield_t status; |
| CHECK_DIF_OK(dif_sram_ctrl_get_status(sram_ctrl, &status)); |
| return status & kDifSramCtrlStatusScrKeyValid; |
| } |
| |
| void sram_ctrl_testutils_scramble(const dif_sram_ctrl_t *sram_ctrl) { |
| CHECK_DIF_OK(dif_sram_ctrl_request_new_key(sram_ctrl)); |
| |
| // Calculate the timeout time. |
| // The SRAM Controller documentation says that it takes approximately 800 |
| // cycles to perform the SRAM scrambling operation (50 cycles were added to |
| // this number to be on a safe side). |
| // |
| // The calculation is equivalent of (1us / clk) * 850 (clock period expressed |
| // in micro seconds multiplied by number of cycles needed to perform |
| // the RAM scrambling operation). |
| // |
| // Expressing this calculation in 1us / (clk / 850) is less intuitive, but |
| // makes more sense when dealing with the integer division, as when the clock |
| // frequency is greater than 1 million hertz, the first expression will give |
| // inaccurate results due to clock period being zero. It should not be a |
| // problem with the second version, as clock frequency won't be less than |
| // 850. We add 1 microsecond to account for flooring. |
| uint32_t usec = |
| udiv64_slow(1000000, udiv64_slow(kClockFreqCpuHz, 850, NULL) + 1, NULL); |
| |
| // Loop until new scrambling key has been obtained. |
| LOG_INFO("Waiting for SRAM scrambling to finish"); |
| IBEX_SPIN_FOR(scramble_finished(sram_ctrl), usec); |
| } |
| |
| /** |
| * Checks whether the SRAM wipe operation has finished. |
| */ |
| static bool wipe_finished(const dif_sram_ctrl_t *sram_ctrl) { |
| dif_sram_ctrl_status_bitfield_t status; |
| CHECK_DIF_OK(dif_sram_ctrl_get_status(sram_ctrl, &status)); |
| return status & kDifSramCtrlStatusInitDone; |
| } |
| |
| void sram_ctrl_testutils_wipe(const dif_sram_ctrl_t *sram_ctrl) { |
| CHECK_DIF_OK(dif_sram_ctrl_wipe(sram_ctrl)); |
| // The timeout calculation is the same as the scramble timeout. |
| uint32_t usec = |
| udiv64_slow(1000000, udiv64_slow(kClockFreqCpuHz, 850, NULL) + 1, NULL); |
| LOG_INFO("Waiting for SRAM wipe to finish"); |
| IBEX_SPIN_FOR(wipe_finished(sram_ctrl), usec); |
| } |
| |
| void sram_ctrl_testutils_check_backdoor_write(uintptr_t backdoor_addr, |
| uint32_t num_words, |
| uint32_t offset_addr, |
| const uint8_t *expected_bytes) { |
| mmio_region_t mem_region = mmio_region_from_addr(backdoor_addr); |
| uint32_t backdoor_data[num_words]; |
| uint32_t expected_data[num_words]; |
| |
| for (int i = 0; i < num_words; ++i) { |
| backdoor_data[i] = |
| mmio_region_read32(mem_region, sizeof(uint32_t) * (offset_addr + i)); |
| // The expected data bytes are organized little-endian. |
| expected_data[i] = expected_bytes[(i * sizeof(uint32_t)) + 3] << 24 | |
| expected_bytes[(i * sizeof(uint32_t)) + 2] << 16 | |
| expected_bytes[(i * sizeof(uint32_t)) + 1] << 8 | |
| expected_bytes[(i * sizeof(uint32_t))]; |
| CHECK(backdoor_data[i] == expected_data[i]); |
| } |
| } |