| // 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]); | |
| } | |
| } |