1 /*
2 * Copyright (c) 2017 Oticon A/S
3 * Copyright (c) 2023 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 /*
9 * Native simulator entry point (main)
10 *
11 * Documentation can be found starting in docs/README.md
12 */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <stdbool.h>
17 #include "nsi_cpun_if.h"
18 #include "nsi_tasks.h"
19 #include "nsi_cmdline_main_if.h"
20 #include "nsi_utils.h"
21 #include "nsi_hw_scheduler.h"
22 #include "nsi_config.h"
23 #include "nsi_cpu_ctrl.h"
24
nsi_exit_inner(int exit_code)25 int nsi_exit_inner(int exit_code)
26 {
27 static int max_exit_code;
28 int cpu_ret;
29
30 max_exit_code = NSI_MAX(exit_code, max_exit_code);
31 /*
32 * nsif_cpun_cleanup may not return if this is called from a SW thread,
33 * but instead it would get nsi_exit() recalled again
34 * ASAP from the HW thread
35 */
36 for (int i = 0; i < NSI_N_CPUS; i++) {
37 cpu_ret = nsif_cpun_cleanup(i);
38 max_exit_code = NSI_MAX(cpu_ret, max_exit_code);
39 }
40
41 nsi_run_tasks(NSITASK_ON_EXIT_PRE_LEVEL);
42 nsi_hws_cleanup();
43 nsi_run_tasks(NSITASK_ON_EXIT_POST_LEVEL);
44 return max_exit_code;
45 }
46
nsi_exit(int exit_code)47 NSI_FUNC_NORETURN void nsi_exit(int exit_code)
48 {
49 exit(nsi_exit_inner(exit_code));
50 }
51
52 /**
53 * Run all early native simulator initialization steps, including command
54 * line parsing and CPU start, until we are ready to let the HW models
55 * run via nsi_hws_one_event()
56 *
57 * Note: This API should normally only be called by the native simulator main()
58 */
nsi_init(int argc,char * argv[])59 void nsi_init(int argc, char *argv[])
60 {
61 /*
62 * Let's ensure that even if we are redirecting to a file, we get stdout
63 * and stderr line buffered (default for console)
64 * Note that glibc ignores size. But just in case we set a reasonable
65 * number in case somebody tries to compile against a different library
66 */
67 setvbuf(stdout, NULL, _IOLBF, 512);
68 setvbuf(stderr, NULL, _IOLBF, 512);
69
70 nsi_run_tasks(NSITASK_PRE_BOOT_1_LEVEL);
71 for (int i = 0; i < NSI_N_CPUS; i++) {
72 nsif_cpun_pre_cmdline_hooks(i);
73 }
74
75 nsi_handle_cmd_line(argc, argv);
76
77 nsi_run_tasks(NSITASK_PRE_BOOT_2_LEVEL);
78 for (int i = 0; i < NSI_N_CPUS; i++) {
79 nsif_cpun_pre_hw_init_hooks(i);
80 }
81
82 nsi_run_tasks(NSITASK_HW_INIT_LEVEL);
83 nsi_hws_init();
84
85 nsi_run_tasks(NSITASK_PRE_BOOT_3_LEVEL);
86
87 nsi_cpu_auto_boot();
88
89 nsi_run_tasks(NSITASK_FIRST_SLEEP_LEVEL);
90 }
91
92 /**
93 * Execute the simulator for at least the specified timeout, then
94 * return. Note that this does not affect event timing, so the "next
95 * event" may be significantly after the request if the hardware has
96 * not been configured to e.g. send an interrupt when expected.
97 *
98 * Note: This API should normally only be called by the native simulator main()
99 */
nsi_exec_for(uint64_t us)100 void nsi_exec_for(uint64_t us)
101 {
102 uint64_t start = nsi_hws_get_time();
103
104 do {
105 nsi_hws_one_event();
106 } while (nsi_hws_get_time() < (start + us));
107 }
108
109 #ifndef NSI_NO_MAIN
110
111 /**
112 *
113 * Note that this main() is not used when building fuzz cases,
114 * as libfuzzer has its own main(),
115 * and calls the "OS" through a per-case fuzz test entry point.
116 */
main(int argc,char * argv[])117 int main(int argc, char *argv[])
118 {
119 nsi_init(argc, argv);
120 while (true) {
121 nsi_hws_one_event();
122 }
123
124 /* This line should be unreachable */
125 return 1; /* LCOV_EXCL_LINE */
126 }
127
128 #endif /* NSI_NO_MAIN */
129