1 /*
2 * Copyright (c) 2017-2018 Oticon A/S
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <zephyr/init.h>
7 #include <stdint.h>
8 #include <string.h>
9 #include "bs_types.h"
10 #include "bs_tracing.h"
11 #include "bstests.h"
12 #include "bs_oswrap.h"
13 #include "nsi_host_trampolines.h"
14
15 /*
16 * Result of the testcase execution.
17 * Note that the executable will return the maximum of bst_result and
18 * {the HW model return code} to the shell and that
19 * {the HW model return code} will be 0 unless it fails or it is
20 * configured illegally
21 */
22 enum bst_result_t bst_result;
23
24 static struct bst_test_instance *current_test;
25 static struct bst_test_list *test_list_top;
26
27 __attribute__((weak)) bst_test_install_t test_installers[] = { NULL };
28
bst_add_tests(struct bst_test_list * tests,const struct bst_test_instance * test_def)29 struct bst_test_list *bst_add_tests(struct bst_test_list *tests,
30 const struct bst_test_instance *test_def)
31 {
32 int idx = 0;
33 struct bst_test_list *tail = tests;
34 struct bst_test_list *head = tests;
35
36 if (tail) {
37 /* First we 'run to end' */
38 while (tail->next) {
39 tail = tail->next;
40 }
41 } else {
42 if (test_def[idx].test_id != NULL) {
43 head = bs_malloc(sizeof(struct bst_test_list));
44 head->next = NULL;
45 head->test_instance = (struct bst_test_instance *)
46 &test_def[idx++];
47 tail = head;
48 }
49 }
50
51 while (test_def[idx].test_id != NULL) {
52 tail->next = bs_malloc(sizeof(struct bst_test_list));
53 tail = tail->next;
54 tail->test_instance = (struct bst_test_instance *)
55 &test_def[idx++];
56 tail->next = NULL;
57 }
58
59 return head;
60 }
61
bst_test_find(struct bst_test_list * tests,char * test_id)62 static struct bst_test_instance *bst_test_find(struct bst_test_list *tests,
63 char *test_id)
64 {
65 struct bst_test_list *top = tests;
66
67 while (top != NULL) {
68 if (!strcmp(top->test_instance->test_id, test_id)) {
69 /* Match found */
70 return top->test_instance;
71 }
72 top = top->next;
73 }
74 return NULL;
75 }
76
bst_install_tests(void)77 __noubsan void bst_install_tests(void)
78 {
79 int idx = 0;
80
81 if (test_list_top) {
82 /* Tests were already installed */
83 return;
84 }
85
86 /* First execute installers until first test was installed */
87 while (!test_list_top && test_installers[idx]) {
88 test_list_top = test_installers[idx++](test_list_top);
89 }
90
91 /* After that simply add remaining tests to list */
92 while (test_installers[idx]) {
93 test_installers[idx++](test_list_top);
94 }
95 }
96
97 /**
98 * Print the tests list displayed with the --testslist command
99 * line option
100 */
bst_print_testslist(void)101 void bst_print_testslist(void)
102 {
103 struct bst_test_list *top;
104
105 /* Install tests */
106 bst_install_tests();
107
108 top = test_list_top;
109 while (top) {
110 bs_trace_raw(0, "TestID: %-10s\t%s\n",
111 top->test_instance->test_id,
112 top->test_instance->test_descr);
113 top = top->next;
114 }
115 }
116
117 /**
118 * Select the testcase to be run from its id
119 */
bst_set_testapp_mode(char * test_id)120 void bst_set_testapp_mode(char *test_id)
121 {
122 /* Install tests */
123 bst_install_tests();
124
125 /* By default all tests start as in progress */
126 bst_result = In_progress;
127
128 current_test = bst_test_find(test_list_top, test_id);
129 if (!current_test) {
130 bs_trace_error_line("test id %s doesn't exist\n", test_id);
131 }
132 }
133
134 /**
135 * Pass to the testcase the command line arguments it may have
136 *
137 * This function is called after bst_set_testapp_mode
138 * and before *init_f
139 */
bst_pass_args(int argc,char ** argv)140 void bst_pass_args(int argc, char **argv)
141 {
142 if (current_test && current_test->test_args_f) {
143 current_test->test_args_f(argc, argv);
144 }
145 }
146
147 /**
148 * Will be called before the CPU is booted
149 */
bst_pre_init(void)150 void bst_pre_init(void)
151 {
152 if (current_test && current_test->test_pre_init_f) {
153 current_test->test_pre_init_f();
154 }
155 }
156
157 /**
158 * Will be called when the CPU has gone to sleep for the first time
159 */
bst_post_init(void)160 void bst_post_init(void)
161 {
162 if (current_test && current_test->test_post_init_f) {
163 current_test->test_post_init_f();
164 }
165 }
166
167 /**
168 * Will be called each time the bstest_ticker timer is triggered
169 */
bst_tick(bs_time_t time)170 void bst_tick(bs_time_t time)
171 {
172
173 if (current_test == NULL) {
174 return;
175 }
176
177 if (current_test->test_tick_f) {
178 current_test->test_tick_f(time);
179 } else if (current_test->test_id) {
180 bs_trace_error_line("the test id %s doesn't have a tick handler"
181 " (how come did we arrive here?)\n",
182 current_test->test_id);
183 }
184
185 }
186
bst_irq_sniffer(int irq_number)187 bool bst_irq_sniffer(int irq_number)
188 {
189 if (current_test && current_test->test_irq_sniffer_f) {
190 return current_test->test_irq_sniffer_f(irq_number);
191 } else {
192 return false;
193 }
194 }
195
bst_fake_device_driver_pre2_init(void)196 static int bst_fake_device_driver_pre2_init(void)
197 {
198 if (current_test && current_test->test_fake_ddriver_prekernel_f) {
199 current_test->test_fake_ddriver_prekernel_f();
200 }
201 return 0;
202 }
203
bst_fake_device_driver_post_init(void)204 static int bst_fake_device_driver_post_init(void)
205 {
206 if (current_test && current_test->test_fake_ddriver_postkernel_f) {
207 current_test->test_fake_ddriver_postkernel_f();
208 }
209 return 0;
210 }
211
212 SYS_INIT(bst_fake_device_driver_pre2_init, PRE_KERNEL_1, 0);
213 SYS_INIT(bst_fake_device_driver_post_init, POST_KERNEL, 0);
214
bst_main(void)215 void bst_main(void)
216 {
217 if (current_test && current_test->test_main_f) {
218 current_test->test_main_f();
219 }
220 }
221
222 /**
223 * Will be called when the device is being terminated
224 */
bst_delete(void)225 uint8_t bst_delete(void)
226 {
227 static bool already_deleted;
228
229 if (already_deleted) {
230 return bst_result;
231 }
232 already_deleted = true;
233
234 if (current_test && current_test->test_delete_f) {
235 current_test->test_delete_f();
236 }
237
238 while (test_list_top) {
239 struct bst_test_list *tmp = test_list_top->next;
240
241 nsi_host_free(test_list_top);
242 test_list_top = tmp;
243 }
244
245 if (bst_result == In_progress) {
246 bs_trace_raw_time(2, "TESTCASE NOT PASSED at exit (test return "
247 "(%u) indicates it was still in progress)\n", bst_result);
248 } else if (bst_result != Passed) {
249 bs_trace_raw_time(2, "The TESTCASE FAILED (test return code %u)\n",
250 bst_result);
251 }
252
253 return bst_result;
254 }
255
256 #if defined(CONFIG_NATIVE_SIMULATOR_MCU_N)
257 #include "bstest_ticker.h"
258
bst_ticker_set_period(bs_time_t tick_period)259 void bst_ticker_set_period(bs_time_t tick_period)
260 {
261 bst_ticker_amp_set_period(CONFIG_NATIVE_SIMULATOR_MCU_N, tick_period);
262 }
263
bst_ticker_set_next_tick_absolute(bs_time_t time)264 void bst_ticker_set_next_tick_absolute(bs_time_t time)
265 {
266 bst_ticker_amp_set_next_tick_absolutelute(CONFIG_NATIVE_SIMULATOR_MCU_N, time);
267 }
268
bst_ticker_set_next_tick_delta(bs_time_t time)269 void bst_ticker_set_next_tick_delta(bs_time_t time)
270 {
271 bst_ticker_amp_set_next_tick_delta(CONFIG_NATIVE_SIMULATOR_MCU_N, time);
272 }
273
bst_awake_cpu_asap(void)274 void bst_awake_cpu_asap(void)
275 {
276 bst_ticker_amp_awake_cpu_asap(CONFIG_NATIVE_SIMULATOR_MCU_N);
277 }
278
279 #endif /* defined(CONFIG_NATIVE_SIMULATOR_MCU_N) */
280