Software APIs
rv_core_ibex_mem_test.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 /**
5  * RV Core Ibex Memory Smoke Test
6  *
7  * This test runs checks access to each kind of memory from the Ibex.
8  *
9  * It is expected to run from SRAM,
10  * so will fail if SRAM read, write or execution does.
11  *
12  * A known location in ROM which contains a `c.jr x1` instruction is read from
13  * and executed. A location is flash is written with a `jalr x0, 0(x1)`
14  * instruction, which is a again read from and executed. In both these cases
15  * execution is tested with the instruction cache disabled and enabled.
16  *
17  * Two MMIO registers from two different devices are written to and read from.
18  */
19 
22 #include "sw/device/lib/base/csr.h"
27 #include "sw/device/lib/runtime/pmp.h"
29 #include "sw/device/lib/testing/flash_ctrl_testutils.h"
30 #include "sw/device/lib/testing/pinmux_testutils.h"
31 #include "sw/device/lib/testing/test_framework/check.h"
32 #include "sw/device/lib/testing/test_framework/ottf_test_config.h"
33 #include "sw/device/lib/testing/test_framework/status.h"
35 
36 #include "flash_ctrl_regs.h"
38 #include "pwm_regs.h"
39 #include "rv_timer_regs.h"
40 
41 OTTF_DEFINE_TEST_CONFIG();
42 
43 enum {
44  // Search within this ROM region to find `c.jr x1`, so execution can be
45  // tested.
46  kRomTestLocStart = TOP_EARLGREY_ROM_BASE_ADDR + 0x400,
47  kRomTestLocEnd = TOP_EARLGREY_ROM_BASE_ADDR + 0x500,
48  kRomTestLocContent = 0x8082,
49 
50  // Number of bytes per page.
51  kFlashBytesPerPage = FLASH_CTRL_PARAM_BYTES_PER_PAGE,
52 
53  // Number of pages allocated to the ROM_EXT. The same number of pages are
54  // allocated at the begining of each data bank.
55  kRomExtPageCount = CHIP_ROM_EXT_SIZE_MAX / kFlashBytesPerPage,
56 
57  // The start page used by this test. Points to the start of the owner
58  // partition in bank 1, otherwise known as owner partition B.
59  kBank1StartPageNum = 256 + kRomExtPageCount,
60 
62  kBank1StartPageNum * kFlashBytesPerPage,
63 };
64 
65 // The flash test location is set to the encoding of `jalr x0, 0(x1)`
66 // so execution can be tested.
67 const uint32_t kFlashTestLocContent = 0x00008067;
68 void (*flash_test_gadget)(void) = (void (*)(void))kFlashTestLoc;
69 
70 volatile uint32_t *kMMIOTestLoc1 =
71  (uint32_t *)(TOP_EARLGREY_RV_TIMER_BASE_ADDR +
72  RV_TIMER_COMPARE_LOWER0_0_REG_OFFSET);
73 const uint32_t kMMIOTestLoc1Content = 0x126d8c15; // a random value
74 
75 volatile uint32_t *kMMIOTestLoc2 =
76  (uint32_t *)(TOP_EARLGREY_PWM_AON_BASE_ADDR + PWM_DUTY_CYCLE_0_REG_OFFSET);
77 const uint32_t kMMIOTestLoc2Content = 0xe4210e64; // a random value
78 
79 /**
80  * Sets up the UART connection.
81  */
82 static void setup_uart(void) {
83  // DIF handles
84  static dif_uart_t uart0;
85  static dif_pinmux_t pinmux;
86 
87  // Initialise DIF handles
88  CHECK_DIF_OK(dif_pinmux_init(
90  CHECK_DIF_OK(dif_uart_init(
92 
93  // Initialise UART console.
94  pinmux_testutils_init(&pinmux);
95  CHECK(kUartBaudrate <= UINT32_MAX, "kUartBaudrate must fit in uint32_t");
96  CHECK(kClockFreqPeripheralHz <= UINT32_MAX,
97  "kClockFreqPeripheralHz must fit in uint32_t");
98  CHECK_DIF_OK(dif_uart_configure(
99  &uart0, (dif_uart_config_t){
100  .baudrate = (uint32_t)kUartBaudrate,
101  .clk_freq_hz = (uint32_t)kClockFreqPeripheralHz,
102  .parity_enable = kDifToggleDisabled,
103  .parity = kDifUartParityEven,
104  .tx_enable = kDifToggleEnabled,
105  .rx_enable = kDifToggleEnabled,
106  }));
107  base_uart_stdout(&uart0);
108 }
109 
110 /**
111  * Enable/disable icache
112  *
113  * @param enable whether or not icache should be enabled
114  */
115 static void use_icache(bool enable) {
116  if (enable) {
117  CSR_SET_BITS(CSR_REG_CPUCTRL, 1);
118  } else {
119  CSR_CLEAR_BITS(CSR_REG_CPUCTRL, 1);
120  }
121  uint32_t csr;
122  CSR_READ(CSR_REG_CPUCTRL, &csr);
123  CHECK((csr & 1) == enable, "Couldn't enable or disable icache.");
124 }
125 
126 /**
127  * Sets up the flash test location.
128  */
129 static void setup_flash(void) {
130  // Create a PMP region for the flash
131  pmp_region_config_t config = {
132  .lock = kPmpRegionLockLocked,
133  .permissions = kPmpRegionPermissionsReadWriteExecute,
134  };
135  pmp_region_configure_napot_result_t result = pmp_region_configure_napot(
137  CHECK(result == kPmpRegionConfigureNapotOk,
138  "Load configuration failed, error code = %d", result);
139  // When running as ROM_EXT, ROM configures the flash memory to be readonly.
140  // We need to execute so we need to unconfigure it.
141  // This region is unconfigured by ROM_EXT so is no-op for silicon owner stage.
142  pmp_region_configure_result_t configure_result =
143  pmp_region_configure_off(5, 0);
144  CHECK(configure_result == kPmpRegionConfigureOk,
145  "Load configuration failed, error code = %d", configure_result);
146 
147  // Initialise the flash controller.
148  dif_flash_ctrl_state_t flash_ctrl;
149  CHECK_DIF_OK(dif_flash_ctrl_init_state(
150  &flash_ctrl,
152 
153  CHECK_STATUS_OK(flash_ctrl_testutils_wait_for_init(&flash_ctrl));
154 
155  dif_flash_ctrl_region_properties_t region_properties = {
156  .rd_en = kMultiBitBool4True,
157  .prog_en = kMultiBitBool4True,
158  .erase_en = kMultiBitBool4True,
159  .scramble_en = kMultiBitBool4False,
160  .ecc_en = kMultiBitBool4False,
161  .high_endurance_en = kMultiBitBool4False};
163  .base = kBank1StartPageNum, .size = 0x1, .properties = region_properties};
164 
165  CHECK_DIF_OK(
166  dif_flash_ctrl_set_data_region_properties(&flash_ctrl, 0, data_region));
167  CHECK_DIF_OK(dif_flash_ctrl_set_data_region_enablement(&flash_ctrl, 0,
169 
170  // Make flash executable
171  CHECK_DIF_OK(
173 
174  // Write the wanted value to flash
175  CHECK_STATUS_OK(flash_ctrl_testutils_erase_and_write_page(
176  /*flash_state=*/&flash_ctrl,
177  /*byte_address=*/kFlashTestLoc,
178  /*partition_id=*/0,
179  /*data=*/&kFlashTestLocContent,
180  /*partition_type=*/kDifFlashCtrlPartitionTypeData,
181  /*word_count=*/1));
182 }
183 
184 /**
185  * The entry point of the SRAM test.
186  */
187 bool test_main(void) {
188  setup_uart();
189 
190  // ROM access is blocked in the silicon owner stage.
191  if (kBootStage != kBootStageOwner) {
192  LOG_INFO("Testing Load from ROM Location.");
193 
194  // For the execution test we a specific `c.jr x1` (i.e. function return)
195  // instruction. Since the address can vary between ROM builds, we scan a
196  // small region to find it.
197  volatile uint16_t *test_loc;
198  for (test_loc = (uint16_t *)kRomTestLocStart;
199  test_loc < (uint16_t *)kRomTestLocEnd; test_loc++) {
200  if (*test_loc == kRomTestLocContent) {
201  break;
202  }
203  }
204  CHECK(test_loc != (uint16_t *)kRomTestLocEnd,
205  "Couldn't find the expected content in ROM test location.");
206  LOG_INFO("Found the expected content at 0x%p", test_loc);
207  void (*rom_test_gadget)(void) = (void (*)(void))test_loc;
208 
209  use_icache(false);
210  LOG_INFO("Running an instruction from ROM with icache disabled.");
211  rom_test_gadget();
212 
213  use_icache(true);
214  LOG_INFO("Running an instruction from ROM with icache enabled.");
215  rom_test_gadget();
216  }
217 
218  LOG_INFO("Testing Store to and Load from MMIO Location 1");
219  *kMMIOTestLoc1 = kMMIOTestLoc1Content;
220  uint32_t load = *kMMIOTestLoc1;
221  CHECK(
222  load == kMMIOTestLoc1Content,
223  "The content of the MMIO address was 0x%08x and not the expected value.",
224  load);
225 
226  LOG_INFO("Testing Store to and Load from MMIO Location 2");
227  *kMMIOTestLoc2 = kMMIOTestLoc2Content;
228  load = *kMMIOTestLoc2;
229  CHECK(
230  load == kMMIOTestLoc2Content,
231  "The content of the MMIO address was 0x%08x and not the expected value.",
232  load);
233 
234  LOG_INFO("Setting up the flash test location.");
235  setup_flash();
236 
237  LOG_INFO("Check flash load");
238  load = *(volatile const uint32_t *)kFlashTestLoc;
239  CHECK(
240  load == kFlashTestLocContent,
241  "The content of the Flash address was 0x%08x and not the expected value.",
242  load);
243 
244  use_icache(false);
245  LOG_INFO("Running an instruction from Flash with icache disabled.");
246  flash_test_gadget();
247  use_icache(true);
248  LOG_INFO("Running an instruction from Flash with icache enabled.");
249  flash_test_gadget();
250 
251  test_status_set(kTestStatusPassed);
252  return true;
253 }