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