Software APIs
ottf_main.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 
6 
7 #include <assert.h>
8 #include <stddef.h>
9 
10 #include "dt/dt_rstmgr.h"
11 #include "dt/dt_rv_core_ibex.h"
12 #include "external/freertos/include/FreeRTOS.h"
13 #include "external/freertos/include/queue.h"
14 #include "external/freertos/include/task.h"
20 #include "sw/device/lib/dif/dif_rv_core_ibex.h"
24 #include "sw/device/lib/testing/rand_testutils.h"
25 #include "sw/device/lib/testing/test_framework/FreeRTOSConfig.h"
26 #include "sw/device/lib/testing/test_framework/check.h"
27 #include "sw/device/lib/testing/test_framework/coverage.h"
28 #include "sw/device/lib/testing/test_framework/ottf_console.h"
29 #include "sw/device/lib/testing/test_framework/ottf_isrs.h"
30 #include "sw/device/lib/testing/test_framework/ottf_test_config.h"
31 #include "sw/device/lib/testing/test_framework/status.h"
32 #include "sw/device/silicon_creator/lib/manifest_def.h"
33 
34 #define MODULE_ID MAKE_MODULE_ID('o', 't', 'm')
35 
36 // Check layout of test configuration struct since OTTF ISR asm code requires a
37 // specific layout.
38 OT_ASSERT_MEMBER_OFFSET(ottf_test_config_t, enable_concurrency, 0);
39 OT_ASSERT_MEMBER_SIZE(ottf_test_config_t, enable_concurrency, 1);
40 
41 // Pointer to the current FreeRTOS Task Control Block, which should be non-NULL
42 // when OTTF concurrency is enabled, and test code is executed within FreeRTOS
43 // tasks.
44 extern void *pxCurrentTCB;
45 
46 // A global random number generator testutil handle.
47 rand_testutils_rng_t rand_testutils_rng_ctx;
48 
49 // The OTTF overrides the default machine ecall exception handler to implement
50 // FreeRTOS context switching, required for supporting cooperative scheduling.
51 void ottf_machine_ecall_handler(uint32_t *exc_info) {
52  if (pxCurrentTCB != NULL) {
53  // If the pointer to the current TCB is not NULL, we are operating in
54  // concurrency mode. In this case, our default behavior is to assume a
55  // context switch has been requested.
56  vTaskSwitchContext();
57  return;
58  }
59  LOG_ERROR(
60  "OTTF currently only supports use of machine-mode ecall for FreeRTOS "
61  "context switching.");
62 }
63 
64 bool ottf_task_create(TaskFunction_t task_function, const char *task_name,
65  configSTACK_DEPTH_TYPE task_stack_depth,
66  uint32_t task_priority) {
67  return xTaskCreate(/*pvTaskCode=*/task_function, /*pcName=*/task_name,
68  /*usStackDepth=*/task_stack_depth, /*pvParameters=*/NULL,
69  /*uxPriority=*/tskIDLE_PRIORITY + 1 + task_priority,
70  /*pxCreatedTask=*/NULL) == pdPASS
71  ? true
72  : false;
73 }
74 
75 void ottf_task_yield(void) { taskYIELD(); }
76 
77 void ottf_task_delete_self(void) { vTaskDelete(/*xTask=*/NULL); }
78 
80  return pcTaskGetName(/*xTaskToQuery=*/NULL);
81 }
82 
83 /* Array holding the report statuses.
84  *
85  * This is a weak symbol which means that the test can override it to change its
86  * size. For this reason, it is important to NOT use its size anywhere. To avoid
87  * any errors, we define it at the bottom of the file so the rest the code uses
88  * this declaration that has no size.
89  */
90 extern const size_t kStatusReportListSize;
91 extern status_t status_report_list[];
92 // This is the count for the number of statuses that have been reported so far.
93 // Warning: this may be greater than kStatusReportListSize! When that happens,
94 // we simply overwrite previous values (modulo kStatusReportListSize).
95 static size_t status_report_list_cnt = 0;
96 
97 // Override the status report function to store it in the array above.
98 void status_report(status_t status) {
99  // In case of overflow, we overwrite previous values.
100  status_report_list[status_report_list_cnt % kStatusReportListSize] = status;
101  status_report_list_cnt++;
102 }
103 
104 static void report_test_status(bool result) {
105  // Reinitialize UART before print any debug output if the test clobbered it.
106  if (kDeviceType != kDeviceSimDV) {
107  if (kOttfTestConfig.console.test_may_clobber) {
108  ottf_console_init();
109  }
110  if (!kOttfTestConfig.silence_console_prints) {
111  LOG_INFO("Finished %s", kOttfTestConfig.file);
112  }
113  }
114  // Print the reported status in case of error. Beware that
115  // status_report_list_cnt might be greater than kStatusReportListSize which
116  // means we had to overwrite values.
117  if (!result) {
118  LOG_INFO("Status reported by the test:");
119  // Handle overflow.
120  size_t print_cnt = status_report_list_cnt;
121  if (status_report_list_cnt > kStatusReportListSize) {
122  print_cnt = kStatusReportListSize;
123  }
124  // We print the list backwards like a stack (last report event first).
125  for (size_t i = 1; i <= print_cnt; i++) {
126  size_t idx = (status_report_list_cnt - i) % kStatusReportListSize;
127  LOG_INFO("- %r", status_report_list[idx]);
128  }
129  // Warn about overflow.
130  if (status_report_list_cnt > kStatusReportListSize) {
131  LOG_INFO(
132  "Some statuses have been lost due to the limited size of the list.");
133  }
134  }
135 
136  coverage_send_buffer();
137  test_status_set(result ? kTestStatusPassed : kTestStatusFailed);
138 }
139 
140 // A wrapper function is required to enable `test_main()` and test teardown
141 // logic to be invoked as a FreeRTOS task. This wrapper can be used by tests
142 // that are run on bare-metal.
143 static void test_wrapper(void *task_parameters) {
144  // Invoke test hooks that can be overridden by closed-source code.
145  bool result = manufacturer_pre_test_hook();
146  result = result && test_main();
147  result = result && manufacturer_post_test_hook();
148  report_test_status(result);
149 }
150 
151 void _ottf_main(void) {
152  test_status_set(kTestStatusInTest);
153 
154  // Clear reset reason register.
155  dif_rstmgr_t rstmgr;
156  CHECK_DIF_OK(dif_rstmgr_init_from_dt(kDtRstmgrAon, &rstmgr));
157  if (kOttfTestConfig.clear_reset_reason) {
158  CHECK_DIF_OK(dif_rstmgr_reset_info_clear(&rstmgr));
159  }
160 
161  // Initialize the global rv_plic DIF context for interrupts.
162  // This needs to happen before ottf_console_init.
163  CHECK_DIF_OK(dif_rv_plic_init_from_dt(kDtRvPlic, &ottf_plic));
164 
165  // Initialize the console to enable logging for non-DV simulation platforms.
166  if (kDeviceType != kDeviceSimDV) {
167  ottf_console_init();
168  if (!kOttfTestConfig.silence_console_prints) {
169  LOG_INFO("Running %s", kOttfTestConfig.file);
170  }
171  }
172 
173  // Initialize a global random number generator testutil context to provide
174  // tests with a source of entropy for randomizing test behaviors.
175  dif_rv_core_ibex_t rv_core_ibex;
176  CHECK_DIF_OK(dif_rv_core_ibex_init_from_dt(kDtRvCoreIbex, &rv_core_ibex));
177  rand_testutils_rng_ctx = rand_testutils_init(&rv_core_ibex);
178 
179  // Run the test.
180  if (kOttfTestConfig.enable_concurrency) {
181  // Run `test_main()` in a FreeRTOS task, allowing other FreeRTOS tasks to
182  // be spawned, if requested in the main test task. Note, we spawn the main
183  // test task at a priority level of 0.
184  ottf_task_create(test_wrapper, "test_main", /*task_stack_depth=*/1024, 0);
185  vTaskStartScheduler();
186  } else {
187  // Otherwise, launch `test_main()` on bare-metal.
188  test_wrapper(NULL);
189  }
190 
191  // Unreachable.
192  CHECK(false);
193 }
194 
195 /* Actual declaration of the weak report list. See comment above for context. */
196 #define OTTF_STATUS_REPORT_DEFAULT_LIST_SIZE 10
197 OT_WEAK const size_t kStatusReportListSize =
198  OTTF_STATUS_REPORT_DEFAULT_LIST_SIZE;
199 OT_WEAK status_t status_report_list[OTTF_STATUS_REPORT_DEFAULT_LIST_SIZE];