Software APIs
sram_ctrl_scrambled_access_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 #include <stdbool.h>
6 #include <stdint.h>
7 
8 #include "dt/dt_rstmgr.h"
9 #include "dt/dt_sram_ctrl.h"
12 #include "sw/device/lib/base/multibits.h"
16 #include "sw/device/lib/testing/rand_testutils.h"
17 #include "sw/device/lib/testing/rstmgr_testutils.h"
18 #include "sw/device/lib/testing/sram_ctrl_testutils.h"
19 #include "sw/device/lib/testing/test_framework/check.h"
21 #include "sw/device/lib/testing/test_framework/ottf_utils.h"
22 
23 #include "rstmgr_regs.h" // Generated.
24 #include "sram_ctrl_regs.h" // Generated.
25 
26 OTTF_DEFINE_TEST_CONFIG();
27 
28 enum {
29 /**
30  * Retention SRAM start address (inclusive).
31  */
32 #if defined(OPENTITAN_IS_EARLGREY)
34  kRetRamLastAddr =
35  kRetSramBaseAddr + TOP_EARLGREY_SRAM_CTRL_RET_AON_RAM_SIZE_BYTES - 1,
36 #elif defined(OPENTITAN_IS_DARJEELING)
37  kRetSramBaseAddr = TOP_DARJEELING_SRAM_CTRL_RET_AON_RAM_BASE_ADDR,
38  kRetRamLastAddr =
39  kRetSramBaseAddr + TOP_DARJEELING_SRAM_CTRL_RET_AON_RAM_SIZE_BYTES - 1,
40 #else
41 #error Unsupported top
42 #endif
43 
44  // See `sw/device/silicon_creator/lib/drivers/retention_sram.h`.
45  kRetSramOwnerAddr = kRetSramBaseAddr + 4 + 2048,
46 
47  kTestBufferSizeWords = 16,
48  kTestBufferSizeBytes = kTestBufferSizeWords * sizeof(uint32_t),
49 
50  /**
51  * Note that there are `2^32` valid code words and that each non-valid code
52  * word triggers an error. Therefore, the probability that a random 39-bit
53  * word triggers an error is: `(2^39 - 2^32)/ 2^39 = 127/128`. Then the
54  * probability that all `kPatternTestWords` triggers an errors is
55  * `(127/128)^kPatternTestWords` after re-scrambling.
56  *
57  * The Generic formula:
58  *
59  * (w-i)
60  * 127
61  * Pr(i) = -------- x (w choose i)
62  * w
63  * 128
64  * Where:
65  * w = The number of words tested.
66  * i = The number of words that may not generate errors.
67  * Pr(i) = Probability that i words will not generate an ECC error.
68  *
69  * So for i in (0..3):
70  *
71  * ``` Python
72  * from math import comb
73  * w = 32
74  * t = 0
75  * for i in range(4):
76  * p = ((127**(w-i))/(128**w)) * comb(w,i)
77  * t += p
78  * print(f'Pr({i}): { round(p, 4)},\tsum{{Pr(0-{i})}}: {round(t, 6)}')
79  * ```
80  * ```
81  * Pr(0): 0.778, sum{Pr(0-0)}: 0.778037
82  * Pr(1): 0.196, sum{Pr(0-1)}: 0.974077
83  * Pr(2): 0.0239, sum{Pr(0-2)}: 0.998004
84  * Pr(3): 0.0019, sum{Pr(0-3)}: 0.999888
85  * ```
86  * So by choosing 3 as the floor limit we will a have probability of `1 -
87  * 0.998004 = 0.1996%` that this test would fail randomly due to ECC errors
88  * not being generated.
89  *
90  * Note: Although `kTestBufferSizeWords` is 16 we use 32 to compute the
91  * probability since we perform two tests here RET SRAM and main SRAM.
92  */
93 
94  kEccErrorsFalsePositiveFloorLimit = 3,
95 };
96 
97 static_assert(kTestBufferSizeWords == 16,
98  "kBackdoorTestWords changed, so "
99  "kEccErrorsFalsePositiveFloorLimit should be "
100  "computed again");
101 
102 typedef struct {
103  uint32_t pattern[kTestBufferSizeWords];
104  uint32_t backdoor[kTestBufferSizeWords];
105  uint32_t ecc_error_counter;
107 
108 static scramble_test_frame *scrambling_frame;
109 static scramble_test_frame *reference_frame;
110 
111 static dif_sram_ctrl_t ret_sram;
112 static dif_rstmgr_t rstmgr;
113 
114 /**
115  * Test pattern to be written and read from SRAM.
116  */
117 static const uint32_t kRamTestPattern1[kTestBufferSizeWords] = {
118  0xA5A5A5A5, 0xA23DE94C, 0xD82A4FB0, 0xE3CA4D62, 0xA5A5A5A5, 0xA23DE94C,
119  0xD82A4FB0, 0xE3CA4D62, 0xA5A5A5A5, 0xA23DE94C, 0xD82A4FB0, 0xE3CA4D62,
120  0xA5A5A5A5, 0xA23DE94C, 0xD82A4FB0, 0xE3CA4D62,
121 };
122 
123 /**
124  * Test pattern to be written and read from SRAM.
125  */
126 static const uint32_t kRamTestPattern2[kTestBufferSizeWords] = {
127  0x5A5A5A5A, 0x3CFB4A77, 0x304C6528, 0xFAEFD5CC, 0x5A5A5A5A, 0x3CFB4A77,
128  0x304C6528, 0xFAEFD5CC, 0x5A5A5A5A, 0x3CFB4A77, 0x304C6528, 0xFAEFD5CC,
129  0x5A5A5A5A, 0x3CFB4A77, 0x304C6528, 0xFAEFD5CC,
130 };
131 
132 /**
133  * Expected data for the backdoor write test, to be written from the testbench.
134  */
135 static const uint8_t kBackdoorExpectedBytes[kTestBufferSizeBytes];
136 
137 /**
138  * Performs scrambling, saves the test relevant data and resets the system.
139  *
140  * This code is written in assembly because MAIN SRAM addresses will be
141  * scrambled, which has a similar effect to overwriting with pseudo-random
142  * data. This will thrash the SRAM (including .bss, .data segments and the
143  * stack), effectively rendering the C runtime environment invalid.
144  *
145  * This function saves contents of the `scrambling_frame` struct in the main
146  * SRAM including the data written from the testbench to the RETENTION SRAM,
147  * which is kept intact across the system reboot.
148  */
149 static noreturn void main_sram_scramble(void) {
150  // Copy only the reference pattern in most environments.
151  uint32_t copy_len = sizeof(reference_frame->pattern);
152  // Also copy the backdoor in DV sim. The DV-sim testbench magically corrects
153  // the backdoor data so that its ECC is correct. This won't be true on other
154  // platforms and the number of ECC errors will be doubled.
155  if (kDeviceType == kDeviceSimDV) {
156  copy_len += sizeof(reference_frame->backdoor);
157  }
158 
159  asm volatile(
160  // Save the tests frames addresses before the scrambling.
161  "lw a2, 0(%[mainFrame]) \n"
162  "lw a3, 0(%[retFrame]) \n"
163  // Request the new scrambling key for MAIN SRAM.
164  "li t0, 0x1 \n"
165  "sw t0, %[kSramCtrlOffset](%[kSramCtrlRegsBase]) \n"
166 
167  // Busy loop - waiting for scrambling to finish.
168  ".L_scrambling_busy_loop: \n"
169  " lw t0, %[kSramCtrlStatusOffset](%[kSramCtrlRegsBase]) \n"
170  " andi t0, t0, %[kSramCtrlKeyScrDone] \n"
171  " beqz t0, .L_scrambling_busy_loop \n"
172 
173  // Restore the tests frames addresses after the scrambling.
174  "sw a2, 0(%[mainFrame]) \n"
175  "sw a3, 0(%[retFrame]) \n"
176 
177  // Copy the backdoor and pattern buffers from main to the retention SRAM.
178  "add t1, a3, %[kCopyLen] \n"
179  ".L_buffer_copy_loop: \n"
180  " lw t0, 0(a2) \n"
181  " sw t0, 0(a3) \n"
182  " addi a2, a2, 4 \n"
183  " addi a3, a3, 4 \n"
184  " blt a3, t1, .L_buffer_copy_loop \n"
185 
186  // Trigger the software system reset via the Reset Manager.
187  "li t0, %[kMultiBitTrue] \n"
188  "sw t0, %[kRstMgrResetReq](%[kRstMgrRegsBase]) \n"
189 
190  // Satisfy the `noreturn` promise to the compiler.
191  ".L_infinite_loop: \n"
192  " wfi \n"
193  " j .L_infinite_loop"
194  : /* No outputs. */
195  : [kMultiBitTrue] "I"(kMultiBitBool4True),
196 
197  [kSramCtrlRegsBase] "r"(
198  dt_sram_ctrl_primary_reg_block(kDtSramCtrlMain)),
199  [kSramCtrlOffset] "I"(SRAM_CTRL_CTRL_REG_OFFSET),
200  [kSramCtrlStatusOffset] "I"(SRAM_CTRL_STATUS_REG_OFFSET),
201 
202  [kSramCtrlKeyScrDone] "I"(0x1 << SRAM_CTRL_STATUS_SCR_KEY_VALID_BIT),
203 
204  [mainFrame] "r"(&scrambling_frame), [retFrame] "r"(&reference_frame),
205  [kCopyLen] "r"(copy_len),
206 
207  [kRstMgrRegsBase] "r"(dt_rstmgr_primary_reg_block(kDtRstmgrAon)),
208  [kRstMgrResetReq] "I"(RSTMGR_RESET_REQ_REG_OFFSET)
209  : "t0", "t1", "a2", "a3");
210 
211  OT_UNREACHABLE();
212 }
213 
214 /**
215  * Prepares the buffers.
216  *
217  * Makes sure that both buffers can be read and written to, and are initialized
218  * to the opposite patterns.
219  */
220 static void prepare_sram_for_scrambling(void) {
221  LOG_INFO("Writing to addr 0x%x", scrambling_frame->pattern);
222  // Make sure we can write and read the buffer in SRAM under test.
223  sram_ctrl_testutils_write(
224  (uint32_t)scrambling_frame->pattern,
225  (sram_ctrl_testutils_data_t){.words = kRamTestPattern2,
226  .len = kTestBufferSizeWords});
227  sram_ctrl_testutils_write(
228  (uint32_t)scrambling_frame->pattern,
229  (sram_ctrl_testutils_data_t){.words = kRamTestPattern1,
230  .len = kTestBufferSizeWords});
231 
232  LOG_INFO("Checking addr 0x%x", scrambling_frame->pattern);
233  CHECK_ARRAYS_EQ(scrambling_frame->pattern, kRamTestPattern1,
234  kTestBufferSizeWords);
235 
236  LOG_INFO("Writing to addr 0x%x", reference_frame->pattern);
237  // Make sure we can write and read to the reference SRAM.
238  sram_ctrl_testutils_write(
239  (uint32_t)reference_frame->pattern,
240  (sram_ctrl_testutils_data_t){.words = kRamTestPattern1,
241  .len = kTestBufferSizeWords});
242  sram_ctrl_testutils_write(
243  (uint32_t)reference_frame->pattern,
244  (sram_ctrl_testutils_data_t){.words = kRamTestPattern2,
245  .len = kTestBufferSizeWords});
246  LOG_INFO("Checking addr 0x%x", reference_frame->pattern);
247  CHECK_ARRAYS_EQ(reference_frame->pattern, kRamTestPattern2,
248  kTestBufferSizeWords);
249 }
250 
251 static void execute_main_sram_test(void) {
252  LOG_INFO("ut_backdoor: %x,ut_pattern: %x,ut_ecc_error_counter: %x",
253  scrambling_frame->backdoor, scrambling_frame->pattern,
254  &scrambling_frame->ecc_error_counter);
255  LOG_INFO("ref_backdoor: %x,ref_pattern: %x,ref_ecc_error_counter: %x",
256  reference_frame->backdoor, reference_frame->pattern,
257  &reference_frame->ecc_error_counter);
258  // Reset the Ecc error count.
259  reference_frame->ecc_error_counter = 0;
260 
261  LOG_INFO("Preparing test...");
262  prepare_sram_for_scrambling();
263  LOG_INFO("Scrambling...");
264  main_sram_scramble();
265 }
266 
267 static void check_sram_data(scramble_test_frame *mem_frame) {
268  LOG_INFO("Checking addr 0x%x", mem_frame->pattern);
269  uint32_t tmp_buffer[kTestBufferSizeWords];
270  memcpy(tmp_buffer, (const uint8_t *)mem_frame->pattern, sizeof(tmp_buffer));
271 
272  CHECK_ARRAYS_NE((uint32_t *)tmp_buffer, kRamTestPattern1,
273  kTestBufferSizeWords);
274  CHECK_ARRAYS_NE((uint32_t *)tmp_buffer, kRamTestPattern2,
275  kTestBufferSizeWords);
276 
277  // Decide whether to perform ECC error count checks after memory is scrambled.
278  //
279  // This is not done on CW305/CW310 FPGAs because interrupts for ECC errors are
280  // only triggered when the SecureIbex parameter is enabled. This parameter is
281  // disabled for these boards due to resource constraints. On CW340 and the
282  // other targets, this parameter is enabled.
283  bool check_ecc_errors = false;
284  switch (kDeviceType) {
285  case kDeviceFpgaCw305:
286  case kDeviceFpgaCw310:
287  check_ecc_errors = false;
288  break;
289  case kDeviceFpgaCw340:
290  case kDeviceSilicon:
291  case kDeviceSimDV:
292  case kDeviceSimVerilator:
293  check_ecc_errors = true;
294  break;
295  default:
296  CHECK(false, "Device type not handled: %d", kDeviceType);
297  return;
298  }
299 
300  if (check_ecc_errors) {
301  LOG_INFO("Checking ECC error count of %d",
302  reference_frame->ecc_error_counter);
303  CHECK(reference_frame->ecc_error_counter <= kTestBufferSizeWords);
304 
305  // Statistically there is always a chance that after changing the scrambling
306  // key the ECC bits are correct and no IRQ is triggered. So we tolerate a
307  // minimum of false positives.
308  uint32_t false_positives =
309  kTestBufferSizeWords - reference_frame->ecc_error_counter;
310 
311  CHECK(false_positives <= kEccErrorsFalsePositiveFloorLimit,
312  "Too many expected ECC errors failed to trigger (%d > %d)",
313  false_positives, kEccErrorsFalsePositiveFloorLimit);
314 
315  if (false_positives > 0) {
316  LOG_INFO("Passing with remark: %d words didn't give expected ECC errors",
317  false_positives);
318  }
319  }
320 
321  if (kDeviceType == kDeviceSimDV) {
322  // Reading before comparing just to make sure it will always read all the
323  // words and the right number of ECC errors will be generated.
324  LOG_INFO("Checking backdoor 0x%x", mem_frame->backdoor);
325  uint32_t kBackdoorExpectedWords[kTestBufferSizeWords];
326  memcpy(kBackdoorExpectedWords, kBackdoorExpectedBytes,
327  kTestBufferSizeBytes);
328 
329  CHECK_ARRAYS_EQ(mem_frame->backdoor, kBackdoorExpectedWords,
330  kTestBufferSizeWords);
331  } else {
332  // Outside of DV SIM we can only check that the pattern was scrambled.
333  CHECK_ARRAYS_NE(mem_frame->pattern, kRamTestPattern2, kTestBufferSizeWords);
334  }
335 }
336 
337 static void execute_retention_sram_test(void) {
338  LOG_INFO("Wiping retention sram...");
339  CHECK_DIF_OK(dif_sram_ctrl_wipe(&ret_sram));
340 
341  LOG_INFO("Preparing test...");
342  prepare_sram_for_scrambling();
343 
344  LOG_INFO("Scrambling...");
345  CHECK_STATUS_OK(sram_ctrl_testutils_scramble(&ret_sram));
346 }
347 
348 /**
349  * Override internal IRQ interrupt service routine to count
350  * the number of integrity exceptions.
351  */
352 void ottf_internal_isr(uint32_t *exc_info) {
353  reference_frame->ecc_error_counter++;
354 }
355 
356 typedef enum test_phases {
357  kTestPhaseSetup = 0,
358  kTestPhaseMainSramScramble,
359  kTestPhaseMainSramCheck,
360  kTestPhaseRetSramScramble,
361  kTestPhaseRetSramCheck,
362  kTestPhaseDone,
363 } test_phases_t;
364 
365 // Test phase written by testbench.
366 static volatile const uint8_t kTestPhase = kTestPhaseSetup;
367 const uint32_t kTestPhaseTimeoutUsec = 2500;
368 
369 /**
370  * Synchronise the current test phase with the test bench.
371  *
372  * Note that this is a no-op outside of the DV SIM environment where this test
373  * does not have a test bench.
374  *
375  * @param prior_phase The phase before the sync.
376  * @param next_phase The phase expected after the sync.
377  * @return The status of the synchronisation.
378  */
379 static status_t sync_testbench(uint8_t prior_phase, uint8_t next_phase) {
380  if (kDeviceType == kDeviceSimDV) {
381  // Set WFI status for testbench synchronization,
382  // no actual WFI instruction is issued.
383  test_status_set(kTestStatusInWfi);
384  test_status_set(kTestStatusInTest);
385 
386  IBEX_TRY_SPIN_FOR(OTTF_BACKDOOR_READ(kTestPhase) != prior_phase,
387  kTestPhaseTimeoutUsec);
388 
389  TRY_CHECK(kTestPhase == next_phase);
390  }
391 
392  return OK_STATUS();
393 }
394 
395 /**
396  * Executes the MAIN SRAM and RET SRAM scrambling test.
397  *
398  * - Set the retention SRAM address to the Owner space range.
399  * - Set a random address to the main SRAM in between the heap and stack.
400  * - Set the reference memory as the retention SRAM and the scrambling as the
401  * main SRAM.
402  * - Inform the address to the testbench using `INFO_LOG`.
403  * - Prepare the main and retention memory for the test by writing a pattern to
404  * them. In both cases, we write two patterns and double check that only the
405  * second pattern is actually stored in the memory.
406  * - Save the reference and scrambling frames pointers from the registers.
407  * - Request a new scrambling key for the main memory. This will only
408  * re-scramble the main memory - the retention memory will remain intact!
409  * - Restore the reference and scrambling frames pointers to registers.
410  * - The backdoor sequence triggers once the new scrambling key becomes valid,
411  * and writes random, but correctly scrambled and ECC encoded data to the main
412  * memory.
413  * - Copy the contents of the `scrambling_frame` to the `reference_frame` except
414  * the `ecc_error_counter` to be verified later.
415  * - Reset the chip to restore the c runtime.
416  * - We check that the `reference_frame` does not match any of the test
417  * patterns.
418  * - Check the ECC error counter.
419  * - Check that the backdoor written data in the `reference_frame`, matches with
420  * the data supplied by the testbench.
421  * - Pick a random address in the retention SRAM range.
422  * - Set the reference memory as the main SRAM and the scrambling as the ret
423  * SRAM and repeat the test except that it is neither necessary to copy the
424  * `scrambling_frame` to the `reference_frame` nor reset the chip before the
425  * checking.
426  *
427  * The control flow between this test software and the testbench is:
428  *
429  * +-----------------------------+------------------------------+
430  * | Software | Testbench |
431  * |-----------------------------|------------------------------|
432  * | Send addresses over UART ---> Receive addresses over UART |
433  * |---------------------------SYNC-----------------------------|
434  * | Execute main SRAM test | Write expected data |
435  * | Reset | |
436  * |---------------------------SYNC-----------------------------|
437  * | Check main against expected | |
438  * | Send addresses over UART ---> Receive addresses over UART |
439  * |---------------------------SYNC-----------------------------|
440  * | Execute ret SRAM test | Write expected data |
441  * |---------------------------SYNC-----------------------------|
442  * | Check ret against expected | |
443  * +-----------------------------+------------------------------+
444  */
445 uint32_t main_sram_addr;
446 uint32_t ret_sram_addr;
447 
448 extern uint8_t _stack_start[];
449 extern uint8_t _freertos_heap_start[];
450 
451 bool test_main(void) {
452  CHECK_DIF_OK(dif_rstmgr_init_from_dt(kDtRstmgrAon, &rstmgr));
453 
454  CHECK_DIF_OK(dif_sram_ctrl_init_from_dt(kDtSramCtrlRetAon, &ret_sram));
455 
456  main_sram_addr = OT_ALIGN_MEM(rand_testutils_gen32_range(
457  (uintptr_t)_freertos_heap_start,
458  (uintptr_t)_stack_start - sizeof(scramble_test_frame)));
459 
460  // Note: Any other address range in the ret SRAM may be written during the
461  // boot, which will invalidate the test.
462  ret_sram_addr = OT_ALIGN_MEM(kRetSramOwnerAddr);
463 
464  scrambling_frame = (scramble_test_frame *)main_sram_addr;
465  reference_frame = (scramble_test_frame *)ret_sram_addr;
466 
467  dif_rstmgr_reset_info_bitfield_t info = rstmgr_testutils_reason_get();
468  uint8_t current_phase = kTestPhase;
469  if (info == kDifRstmgrResetInfoPor) {
470  LOG_INFO("RET_SRAM addr: %x MAIN_SRAM addr: %x", ret_sram_addr,
471  main_sram_addr);
472  CHECK_STATUS_OK(sync_testbench(current_phase, kTestPhaseMainSramScramble));
473  LOG_INFO("First boot, testing main sram");
474  // First boot, start with ret sram.
475  execute_main_sram_test();
476 
477  } else if (info == kDifRstmgrResetInfoSw) {
478  CHECK_STATUS_OK(sync_testbench(current_phase, kTestPhaseMainSramCheck));
479  LOG_INFO("Second boot, checking main sram");
480 
481  check_sram_data(reference_frame);
482 
483  LOG_INFO("Testing Retention sram");
484  ret_sram_addr = OT_ALIGN_MEM(rand_testutils_gen32_range(
485  kRetSramBaseAddr, kRetRamLastAddr - sizeof(scramble_test_frame)));
486  LOG_INFO("RET_SRAM addr: %x MAIN_SRAM addr: %x", ret_sram_addr,
487  main_sram_addr);
488  CHECK_STATUS_OK(sync_testbench(current_phase, kTestPhaseRetSramScramble));
489 
490  scrambling_frame = (scramble_test_frame *)ret_sram_addr;
491  reference_frame = (scramble_test_frame *)main_sram_addr;
492 
493  execute_retention_sram_test();
494 
495  CHECK_STATUS_OK(sync_testbench(current_phase, kTestPhaseRetSramCheck));
496  LOG_INFO("Checking retention sram");
497 
498  // Reset the Ecc error count that lies on the main sram.
499  reference_frame->ecc_error_counter = 0;
500  check_sram_data(scrambling_frame);
501 
502  return true;
503  }
504 
505  return false;
506 }