Software APIs
crt_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 <stddef.h>
6 #include <stdint.h>
7 
15 #include "sw/device/lib/testing/test_framework/check.h"
16 #include "sw/device/lib/testing/test_framework/ottf_test_config.h"
17 #include "sw/device/lib/testing/test_framework/status.h"
18 #include "sw/device/silicon_creator/lib/manifest_def.h"
19 
21 
22 OTTF_DEFINE_TEST_CONFIG();
23 
24 // Symbols defined in `sw/device/lib/testing/test_framework/ottf.ld`,
25 // which we use to check that the CRT did what it was supposed to.
26 extern char _bss_start;
27 extern char _bss_end;
28 extern char _data_start;
29 extern char _data_end;
30 extern char _data_init_start;
31 
32 // The addresses of the values above.
33 static const uintptr_t bss_start_addr = (uintptr_t)&_bss_start;
34 static const uintptr_t bss_end_addr = (uintptr_t)&_bss_end;
35 static const uintptr_t data_start_addr = (uintptr_t)&_data_start;
36 static const uintptr_t data_end_addr = (uintptr_t)&_data_end;
37 static const uintptr_t data_init_start_addr = (uintptr_t)&_data_init_start;
38 
39 // Ensure that both .bss and .data are non-empty. The compiler will always keep
40 // these symbols, since they're volatile.
41 volatile char ensure_data_exists = 42;
42 volatile char ensure_bss_exists;
43 
44 static dif_uart_t uart0;
45 static void init_uart(void) {
46  CHECK_DIF_OK(dif_uart_init(
48  CHECK(kUartBaudrate <= UINT32_MAX, "kUartBaudrate must fit in uint32_t");
49  CHECK(kClockFreqPeripheralHz <= UINT32_MAX,
50  "kClockFreqPeripheralHz must fit in uint32_t");
51  CHECK_DIF_OK(dif_uart_configure(
52  &uart0, (dif_uart_config_t){
53  .baudrate = (uint32_t)kUartBaudrate,
54  .clk_freq_hz = (uint32_t)kClockFreqPeripheralHz,
55  .parity_enable = kDifToggleDisabled,
56  .parity = kDifUartParityEven,
57  .tx_enable = kDifToggleEnabled,
58  .rx_enable = kDifToggleEnabled,
59  }));
60  base_uart_stdout(&uart0);
61 }
62 
63 /**
64  * Test that crt_section_clear correctly zeros word aligned sections.
65  *
66  * Sections are simulated using word aligned regions of various sizes within an
67  * array.
68  *
69  * Does not return if the test fails.
70  */
71 static void test_crt_section_clear(void) {
72  // Function to test (symbol in the CRT assembly library).
73  extern void crt_section_clear(void *start, void *end);
74 
75  // Maximum end index of target section.
76  const size_t kLen = 32;
77 
78  // Section indices (start inclusive, end exclusive).
79  const struct {
80  size_t start;
81  size_t end;
82  } kTests[] = {{.start = 0, .end = 0}, {.start = 0, .end = 1},
83  {.start = kLen - 1, .end = kLen}, {.start = 0, .end = kLen - 1},
84  {.start = 1, .end = kLen}, {.start = 0, .end = kLen}};
85 
86  for (size_t t = 0; t < ARRAYSIZE(kTests); ++t) {
87  // Set target array to non-zero values.
88  uint32_t section[kLen];
89  const uint32_t kVal = ~0u;
90  for (size_t i = 0; i < kLen; ++i) {
91  section[i] = kVal;
92  }
93 
94  // Clear section of target array.
95  const size_t start = kTests[t].start;
96  const size_t end = kTests[t].end;
97  crt_section_clear(&section[start], &section[end]);
98 
99  // Check that section was cleared.
100  for (size_t i = 0; i < kLen; ++i) {
101  const uint32_t expect = i >= start && i < end ? 0 : kVal;
102  CHECK(section[i] == expect,
103  "%s case %u: section[%u] got 0x%08x, want 0x%08x", __func__, t, i,
104  section[i], expect);
105  }
106  }
107 }
108 
109 /**
110  * Test that crt_section_copy correctly copies data between word aligned
111  * sections.
112  *
113  * Sections are simulated using word aligned regions of various sizes within
114  * arrays.
115  *
116  * Does not return if the test fails.
117  */
118 static void test_crt_section_copy(void) {
119  // Function to test (symbol in the CRT assembly library).
120  extern void crt_section_copy(void *start, void *end, void *source);
121 
122  // Maximum end index of target section.
123  const size_t kLen = 32;
124 
125  // Section indices (start inclusive, end exclusive) and source index
126  // (inclusive).
127  const struct {
128  size_t start;
129  size_t end;
130  size_t source;
131  } kTests[] = {{.start = 0, .end = 0, .source = 0},
132  {.start = 0, .end = 1, .source = 1},
133  {.start = kLen - 1, .end = kLen, .source = 2},
134  {.start = 0, .end = kLen - 1, .source = 1},
135  {.start = 1, .end = kLen, .source = 1},
136  {.start = 0, .end = kLen, .source = 0},
137  {.start = 0, .end = kLen, .source = 0},
138  {.start = 1, .end = kLen, .source = 0},
139  {.start = 2, .end = kLen, .source = 0},
140  {.start = 3, .end = kLen, .source = 0},
141  {.start = 0, .end = kLen / 2, .source = 0},
142  {.start = 1, .end = kLen / 2, .source = 0},
143  {.start = 2, .end = kLen / 2, .source = 0},
144  {.start = 3, .end = kLen / 2, .source = 0}};
145 
146  for (size_t t = 0; t < ARRAYSIZE(kTests); ++t) {
147  // Clear target array and setup source array with known values (index + 1).
148  uint32_t dst[kLen], src[kLen];
149  for (size_t i = 0; i < kLen; ++i) {
150  src[i] = (uint32_t)(i) + 1;
151  dst[i] = 0;
152  }
153 
154  // Copy section from source to target array.
155  const size_t start = kTests[t].start;
156  const size_t end = kTests[t].end;
157  const size_t source = kTests[t].source;
158  crt_section_copy(&dst[start], &dst[end], &src[source]);
159 
160  // First expected value.
161  uint32_t val = (uint32_t)(source) + 1;
162 
163  // Check section was copied correctly.
164  for (size_t i = 0; i < kLen; ++i) {
165  const uint32_t expect = i >= start && i < end ? val++ : 0;
166  CHECK(dst[i] == expect, "%s case %u: dst[%u] got 0x%08x, want 0x%08x",
167  __func__, t, i, dst[i], expect);
168  }
169  }
170 }
171 
172 void _ottf_main(void) {
173  // NOTE: we cannot call any external functions until all checks of post-CRT
174  // state are complete; this is to ensure that our checks are not tainted by
175  // external functions.
176  //
177  // Among other things, this means we can't CHECK, since we can't initialize
178  // UART. Thus, any critical failures are handled by returning from main.
179  // To minimize the chance of things going wrong, we don't even bother placing
180  // the checks in their own function.
181 
182  // Test core assumptions above the five addresses above. The test code
183  // must be able to assume these all hold.
184  //
185  // Note that performing these comparisons on their addresses is UB, and will
186  // cause this entire function to get deleted by the compiler.
187  if (&_bss_start > &_bss_end || &_data_start > &_data_end) {
188  // Something has gone terribly wrong and we have no hope of continuing the
189  // test, so we're going to just abort.
190  abort();
191  }
192 
193  // Ensure that .bss was *actually* zeroed at the start of execution. If it
194  // wasn't, we note the offset from _bss_start at which it wasn't.
195  char *bss = &_bss_start;
196  ptrdiff_t bss_len = &_bss_end - &_bss_start;
197  int bad_bss_index = -1;
198  for (int i = 0; i < bss_len; ++i) {
199  if (bss[i] != 0) {
200  bad_bss_index = i;
201  break;
202  }
203  }
204 
205  // Similarly, ensure that .data has the values in the init section.
206  char *data = &_data_start;
207  char *data_init = &_data_init_start;
208  ptrdiff_t data_len = &_data_end - &_data_start;
209  int bad_data_index = -1;
210  for (int i = 0; i < data_len; ++i) {
211  if (data[i] != data_init[i]) {
212  bad_data_index = i;
213  break;
214  }
215  }
216 
217  // End of post-CRT checks; begin actual assertions..
218  test_status_set(kTestStatusInTest);
219  // Initialize the UART to enable logging for non-DV simulation platforms.
220  if (kDeviceType != kDeviceSimDV) {
221  init_uart();
222  }
223 
224  CHECK(bss_start_addr % sizeof(uint32_t) == 0,
225  "_bss_start not word-aligned: 0x%08x", bss_start_addr);
226  CHECK(bss_end_addr % sizeof(uint32_t) == 0,
227  "_bss_end not word-aligned: 0x%08x", bss_end_addr);
228  CHECK(data_start_addr % sizeof(uint32_t) == 0,
229  "_data_start not word-aligned: 0x%08x", data_start_addr);
230  CHECK(data_end_addr % sizeof(uint32_t) == 0,
231  "_data_end not word-aligned: 0x%08x", data_end_addr);
232  CHECK(data_init_start_addr % sizeof(uint32_t) == 0,
233  "_data_init_start not word-aligned: 0x%08x", data_init_start_addr);
234 
235  CHECK(bad_bss_index == -1,
236  "found non-zero .bss byte at *(0x%08x + %d) == 0x%02x", bss_start_addr,
237  bad_bss_index, (uint32_t)bss[bad_bss_index]);
238  CHECK(bad_data_index == -1,
239  "found bad .data byte at *(0x%08x + %d) == 0x%02x", data_start_addr,
240  bad_data_index, (uint32_t)data_init[bad_data_index]);
241 
242  // Unit test CRT utility functions.
243  test_crt_section_clear();
244  test_crt_section_copy();
245 
246  test_status_set(kTestStatusPassed);
247 }