Software APIs
rv_core_ibex_epmp_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 
10 #include "sw/device/lib/runtime/pmp.h"
12 #include "sw/device/lib/testing/pinmux_testutils.h"
13 #include "sw/device/lib/testing/test_framework/check.h"
14 #include "sw/device/lib/testing/test_framework/ottf_test_config.h"
15 #include "sw/device/lib/testing/test_framework/status.h"
16 #include "sw/device/silicon_creator/lib/dbg_print.h"
17 #include "sw/device/silicon_creator/lib/epmp_defs.h"
18 
20 
21 OTTF_DEFINE_TEST_CONFIG();
22 
23 /**
24  * Labels
25  */
26 // The end of the rodata region.
27 // This is set in the linker script.
28 extern const char __rodata_end[];
29 // The start and the end of the user's test function.
30 extern const char i_am_become_user[];
31 extern const char kIAmBecomeUserEnd[];
32 // Expected U Mode Instruction Access Fault Return Address
33 extern const char kExpUInstrAccFaultRet[];
34 // Expected M Mode Instruction Access Fault Return Address
35 extern const char kExpMInstrAccFaultRet[];
36 
37 extern void (*finish_test)(void);
38 
39 /**
40  * Diff handles
41  */
42 static dif_uart_t uart0;
43 static dif_pinmux_t pinmux;
44 
45 /**
46  * The location in memory which will be used to test permissions.
47  *
48  * They are set up by `pmp_setup_test_locations` as such:
49  *
50  * | Location | L | R | W | X | U Mode | M Mode |
51  * |----------|---|---|---|---|--------|--------|
52  * | 0 | 0 | 1 | 0 | 0 | R | |
53  * | 1 | 1 | 1 | 1 | 0 | | RW |
54  * | 2 | 0 | 0 | 1 | 0 | R | RW |
55  * | 3 | 1 | 0 | 1 | 1 | X | R X |
56  *
57  * Note: mseccfg.MML is set in this test,
58  * so permissions differ from standard (non-MML) PMP.
59  */
60 enum { kNumLocations = 4 };
61 volatile uint32_t test_locations[kNumLocations] = {
62  // Random Numbers
63  [0] = 0x3779cdc5,
64  [1] = 0x76bce080,
65  [2] = 0xae8a4ed7,
66  // The `ret` instruction. (This region is executable.)
67  [3] = 0x00008067,
68 };
69 
70 static inline bool was_in_machine_mode(void) {
71  uint32_t mstatus;
72  CSR_READ(CSR_REG_MSTATUS, &mstatus);
73  // If both MPP bits are set, then I was in machine mode.
74  const uint32_t kMppOffset = 11;
75  return ((mstatus >> kMppOffset) & 0x3) == 0x3;
76 }
77 
78 void ottf_exception_handler(uint32_t *exc_info) {
79  uint32_t mtval = ibex_mtval_read();
80  ibex_exc_t mcause = ibex_mcause_read();
81  bool m_mode_exception = was_in_machine_mode();
82 
83  // The frame address is the address of the stack location that holds the
84  // `mepc`, since the OTTF exception handler entry code saves the `mepc` to
85  // the top of the stack before transferring control flow to the exception
86  // handler function (which is overridden here). See the `handler_exception`
87  // subroutine in `sw/device/lib/testing/testing/ottf_isrs.S` for more details.
88  uintptr_t *mepc_stack_addr = (uintptr_t *)OT_FRAME_ADDR();
89  uint32_t mpec = *mepc_stack_addr;
90 
91  switch (mcause) {
92  case kIbexExcLoadAccessFault:
93  if (m_mode_exception) {
94  CHECK(mtval == (uint32_t)(test_locations + 0),
95  "Unexpected M Mode Load Access Fault:"
96  " mpec = 0x%08x, mtval = 0x%08x",
97  mpec, mtval);
98  } else {
99  CHECK(mtval == (uint32_t)(test_locations + 1) ||
100  mtval == (uint32_t)(test_locations + 3),
101  "Unexpected U Mode Load Access Fault:"
102  " mpec = 0x%08x, mtval = 0x%08x",
103  mpec, mtval);
104  };
105  break;
106  case kIbexExcStoreAccessFault:
107  if (m_mode_exception) {
108  CHECK(mtval == (uint32_t)(test_locations + 0) ||
109  mtval == (uint32_t)(test_locations + 3),
110  "Unexpected M Mode Store Access Fault:"
111  " mpec = 0x%08x, mtval = 0x%08x",
112  mpec, mtval);
113  } else {
114  CHECK(mtval == (uint32_t)(test_locations + 0) ||
115  mtval == (uint32_t)(test_locations + 1) ||
116  mtval == (uint32_t)(test_locations + 2) ||
117  mtval == (uint32_t)(test_locations + 3),
118  "Unexpected U Mode Store Access Fault:"
119  " mpec = 0x%08x, mtval = 0x%08x",
120  mpec, mtval);
121  };
122  break;
123  case kIbexExcInstrAccessFault:
124  CHECK(mtval == (uint32_t)(test_locations + 0) ||
125  mtval == (uint32_t)(test_locations + 1) ||
126  mtval == (uint32_t)(test_locations + 2),
127  "Unexpected Instruction Access Fault:"
128  " mpec = 0x%08x, mtval = 0x%08x",
129  mpec, mtval);
130  *mepc_stack_addr = m_mode_exception ? (uintptr_t)kExpMInstrAccFaultRet
131  : (uintptr_t)kExpUInstrAccFaultRet;
132  break;
133  case kIbexExcUserECall:
134  test_status_set(kTestStatusPassed);
135  finish_test();
136  OT_UNREACHABLE();
137  default:
138  CHECK(false,
139  "Unexpected Exception:"
140  " mcause = 0x%x, mpec 0x%x, mtval = 0x%x",
141  mcause, mpec, mtval);
142  OT_UNREACHABLE();
143  }
144 }
145 
146 /**
147  * Converts an address to a TOR address field value.
148  *
149  * @param addr The address to convert.
150  * @return The given address encoded as a TOR address field value.
151  */
152 inline uint32_t tor_address(uint32_t addr) { return addr >> 2; }
153 
154 /**
155  * Finds the pmpcfg CSR for a given PMP region.
156  *
157  * @param region PMP region.
158  * @return The address of the pmpcfg CSR of the given region.
159  */
160 inline uint32_t region_pmpcfg(uint32_t region) {
161  switch (region / 4) {
162  case 0:
163  return CSR_REG_PMPCFG0;
164  case 1:
165  return CSR_REG_PMPCFG1;
166  case 2:
167  return CSR_REG_PMPCFG2;
168  case 3:
169  return CSR_REG_PMPCFG3;
170  default:
171  OT_UNREACHABLE();
172  };
173 }
174 
175 /**
176  * Finds offset of a region's configuration in it's pmpcfg CSR.
177  *
178  * @param region PMP region.
179  * @return pmpcfg offset.
180  */
181 inline uint32_t region_offset(uint32_t region) { return region % 4 * 8; }
182 
183 /**
184  * Sets up the execution area of Machine Mode.
185  *
186  * This configuration adjusts the existing configuration from the
187  * [reset PMP configuration](/hw/top_{}/ip_autogen/rtl/ibex_pmp_reset_pkg.sv)
188  * and [SRAM loader](/sw/host/opentitanlib/src/test_utils/load_sram_program.rs).
189  *
190  * These changes are needed before mseccfg.MML is enabled,
191  * because LRWX permissions become read only for machine mode.
192  */
193 static void pmp_setup_machine_area(void) {
194  // Set up the writeable section of the SRAM executable.
195  //
196  // Note: this overlaps a region covering the whole of SRAM (region 15),
197  // but is in a lower PMP register so region 15's configuration
198  // will be ignored in this area.
199  const uint32_t kRodataEnd = (uint32_t)__rodata_end;
200  const uint32_t kSramEnd = TOP_EARLGREY_SRAM_CTRL_MAIN_RAM_BASE_ADDR +
202 
203  CSR_WRITE(CSR_REG_PMPADDR8, tor_address(kRodataEnd));
204  CSR_WRITE(CSR_REG_PMPADDR9, tor_address(kSramEnd));
205 
206  const uint32_t pmp9cfg = EPMP_CFG_A_TOR | EPMP_CFG_LRW;
207  CSR_SET_BITS(region_pmpcfg(9), pmp9cfg << region_offset(1));
208 
209  // Clear the execution permissions on region 11 (MMIO)
210  CSR_CLEAR_BITS(region_pmpcfg(11), EPMP_CFG_X << region_offset(11));
211  uint32_t csr;
212  CSR_READ(region_pmpcfg(11), &csr);
213  CHECK(!((csr >> region_offset(11)) & EPMP_CFG_X),
214  "Couldn't remove execute access to PMP region 11.");
215 
216  // Clear the write permissions on regions 13 (DV ROM) and 15 (all SRAM)
217  CSR_CLEAR_BITS(region_pmpcfg(13), EPMP_CFG_W << region_offset(13));
218  CSR_CLEAR_BITS(region_pmpcfg(15), EPMP_CFG_W << region_offset(15));
219  CSR_READ(region_pmpcfg(13), &csr);
220  CHECK(!((csr >> region_offset(13)) & EPMP_CFG_W),
221  "Couldn't remove write access from PMP region 15.");
222  CHECK(!((csr >> region_offset(15)) & EPMP_CFG_W),
223  "Couldn't remove write access from PMP region 15.");
224 }
225 
226 /**
227  * Sets up the User Mode test function to be executable in user mode.
228  *
229  * *It wouldn't be very useful if it wasn't.*
230  */
231 static void pmp_setup_user_area(void) {
232  const uintptr_t kStart = (uintptr_t)i_am_become_user;
233  const uintptr_t kEnd = (uintptr_t)kIAmBecomeUserEnd;
234 
235  CSR_WRITE(CSR_REG_PMPADDR0, tor_address(kStart));
236  CSR_WRITE(CSR_REG_PMPADDR1, tor_address(kEnd));
237 
238  const uint32_t pmp1cfg = (EPMP_CFG_A_TOR | EPMP_CFG_LRWX) ^ EPMP_CFG_R;
239  CSR_SET_BITS(region_pmpcfg(1), pmp1cfg << region_offset(1));
240 }
241 
242 /**
243  * Sets up the permissions for the test locations.
244  *
245  * See the declaration of `test_locations`
246  * to see the desired permission settings.
247  */
248 static void pmp_setup_test_locations(void) {
249  CSR_WRITE(CSR_REG_PMPADDR3, tor_address((uintptr_t)(test_locations + 0)));
250  CSR_WRITE(CSR_REG_PMPADDR4, tor_address((uintptr_t)(test_locations + 1)));
251  CSR_WRITE(CSR_REG_PMPADDR5, tor_address((uintptr_t)(test_locations + 2)));
252  CSR_WRITE(CSR_REG_PMPADDR6, tor_address((uintptr_t)(test_locations + 3)));
253  CSR_WRITE(CSR_REG_PMPADDR7, tor_address((uintptr_t)(test_locations + 4)));
254 
255  uint32_t cfg = EPMP_CFG_A_TOR | EPMP_CFG_R;
256  CSR_SET_BITS(region_pmpcfg(4), cfg << region_offset(4));
257  cfg = EPMP_CFG_A_TOR | EPMP_CFG_LRW;
258  CSR_SET_BITS(region_pmpcfg(5), cfg << region_offset(5));
259  cfg = EPMP_CFG_A_TOR | EPMP_CFG_W;
260  CSR_SET_BITS(region_pmpcfg(6), cfg << region_offset(6));
261  cfg = EPMP_CFG_A_TOR | EPMP_CFG_L | EPMP_CFG_X | EPMP_CFG_W;
262  CSR_SET_BITS(region_pmpcfg(7), cfg << region_offset(7));
263 }
264 
265 /**
266  * Sets up the UART connection.
267  */
268 static void setup_uart(void) {
269  // Initialise DIF handles
270  CHECK_DIF_OK(dif_pinmux_init(
272  CHECK_DIF_OK(dif_uart_init(
274 
275  // Initialise UART console.
276  pinmux_testutils_init(&pinmux);
277  CHECK(kUartBaudrate <= UINT32_MAX, "kUartBaudrate must fit in uint32_t");
278  CHECK(kClockFreqPeripheralHz <= UINT32_MAX,
279  "kClockFreqPeripheralHz must fit in uint32_t");
280  CHECK_DIF_OK(dif_uart_configure(
281  &uart0, (dif_uart_config_t){
282  .baudrate = (uint32_t)kUartBaudrate,
283  .clk_freq_hz = (uint32_t)kClockFreqPeripheralHz,
284  .parity_enable = kDifToggleDisabled,
285  .parity = kDifUartParityEven,
286  .tx_enable = kDifToggleEnabled,
287  .rx_enable = kDifToggleEnabled,
288  }));
289  base_uart_stdout(&uart0);
290 }
291 
292 /**
293  * The entry point of the SRAM program.
294  *
295  * *Control flow passed from `sram_start`.*
296  */
297 bool test_main(void) {
298  setup_uart();
299 
300  // Must set up the Machine Mode Area Correctly
301  // before entering Machine Mode Lockdown.
302  pmp_setup_machine_area();
303 
304  LOG_INFO("Enable Machine Mode Lockdown");
305  CSR_SET_BITS(CSR_REG_MSECCFG, EPMP_MSECCFG_MML);
306 
307  pmp_setup_user_area();
308  pmp_setup_test_locations();
309 
310  LOG_INFO("The PMP Config:");
311  dbg_print_epmp();
312 
313  LOG_INFO("Machine Mode Tests");
314  uint32_t load;
315  for (size_t loc = 0; loc < kNumLocations; ++loc) {
316  test_locations[loc] = 42;
317  load = test_locations[loc];
318  ((void (*)(void))(test_locations + loc))();
319  // The address to return to after an expected
320  // instruction access fault has occurred.
321  OT_ADDRESSABLE_LABEL(kExpMInstrAccFaultRet);
322  };
323  // Pretending to use load
324  (void)load;
325 
326  LOG_INFO("User Mode Tests");
327  // Jump to the user area to perform user tests.
328  asm volatile(
329  "la t0, i_am_become_user\n"
330  "csrw mepc, t0\n"
331  "mret\n"
332  : // The clobber doesn't really matter;
333  : // we're not comming back.
334  : "t0");
335  OT_UNREACHABLE();
336 }