1use crate::arch::kernel;
2use crate::arch::kernel::core_local::{core_id, core_scheduler};
3use crate::arch::kernel::interrupts;
4use crate::env::{self, StartInfo};
5use crate::scheduler::{PerCoreScheduler, PerCoreSchedulerExt};
6use crate::{console, drivers, executor, fs, logging, mm, scheduler, syscalls};
7
8mod built_info {
9 include!(concat!(env!("OUT_DIR"), "/built.rs"));
10}
11
12#[cfg(feature = "hermit-entry")]
13hermit_entry::define_abi_tag!();
14
15#[cfg(feature = "hermit-entry")]
16hermit_entry::define_entry_version!();
17
18#[cfg(test)]
19#[unsafe(no_mangle)]
20extern "C" fn runtime_entry(_argc: i32, _argv: *const *const u8, _env: *const *const u8) -> ! {
21 println!("Executing hermit unittests. Any arguments are dropped");
22 crate::test_main();
23 core_scheduler().exit(0)
24}
25
26#[cfg(test)]
28pub fn test_runner(tests: &[&dyn Fn()]) {
29 println!("Running {} tests", tests.len());
30 for test in tests {
31 test();
32 }
33 core_scheduler().exit(0)
34}
35
36#[test_case]
37fn trivial_test() {
38 println!("Test test test");
39 panic!("Test called");
40}
41
42extern "C" fn initd(_arg: usize) {
44 unsafe extern "C" {
45 #[cfg(all(not(test), not(any(feature = "nostd", feature = "common-os"))))]
46 fn runtime_entry(argc: i32, argv: *const *const u8, env: *const *const u8) -> !;
47 #[cfg(all(not(test), any(feature = "nostd", feature = "common-os")))]
48 fn main(argc: i32, argv: *const *const u8, env: *const *const u8);
49 }
50
51 drivers::init();
53 fs::init();
55 executor::init();
56
57 syscalls::init();
58 #[cfg(feature = "shell")]
59 crate::shell::init();
60
61 #[cfg(not(test))]
63 let (argc, argv, environ) = syscalls::get_application_parameters();
64
65 core_scheduler().reschedule();
67
68 if cfg!(feature = "warn-prebuilt") {
69 warn!("This is a prebuilt Hermit kernel.");
70 warn!("For non-default device drivers and features, consider building a custom kernel.");
71 }
72
73 info!("Jumping into application");
74
75 #[cfg(not(test))]
76 unsafe {
77 #[cfg(all(not(test), not(any(feature = "nostd", feature = "common-os"))))]
79 runtime_entry(argc, argv, environ);
80 #[cfg(all(not(test), any(feature = "nostd", feature = "common-os")))]
81 main(argc, argv, environ);
82 }
83 #[cfg(test)]
84 crate::test_main();
85}
86
87#[cfg(feature = "smp")]
88fn synch_all_cores() {
89 use core::hint;
90 use core::sync::atomic::{AtomicU32, Ordering};
91
92 static CORE_COUNTER: AtomicU32 = AtomicU32::new(0);
93
94 CORE_COUNTER.fetch_add(1, Ordering::SeqCst);
95
96 let possible_cpus = kernel::get_possible_cpus();
97 while CORE_COUNTER.load(Ordering::SeqCst) != possible_cpus {
98 hint::spin_loop();
99 }
100}
101
102pub fn boot_processor_main() -> ! {
104 use crate::config::USER_STACK_SIZE;
105
106 mm::claim_initial_heap();
108 hermit_sync::Lazy::force(&console::CONSOLE);
109 unsafe {
110 logging::init();
111 }
112
113 info!("Welcome to Hermit {}", env!("CARGO_PKG_VERSION"));
114 if let Some(git_version) = built_info::GIT_VERSION {
115 let dirty = if built_info::GIT_DIRTY == Some(true) {
116 " (dirty)"
117 } else {
118 ""
119 };
120
121 let opt_level = if built_info::OPT_LEVEL == "3" {
122 format_args!("")
123 } else {
124 format_args!(" (opt-level={})", built_info::OPT_LEVEL)
125 };
126
127 info!("Git version: {git_version}{dirty}{opt_level}");
128 }
129 let arch = built_info::TARGET.split_once('-').unwrap().0;
130 info!("Architecture: {arch}");
131 info!("Enabled features: {}", built_info::FEATURES_LOWERCASE_STR);
132 info!("Built on {}", built_info::BUILT_TIME_UTC);
133
134 info!("Executable start: {:p}", elf_symbols::executable_start());
135 info!("ELF header: {:p}", elf_symbols::elf_header());
136 info!("Text segment end: {:p}", elf_symbols::text_end());
137 info!("Data segment end: {:p}", elf_symbols::data_end());
138 info!("Executable end: {:p}", elf_symbols::executable_end());
139
140 info!("{}", env::start_info().display());
141
142 kernel::boot_processor_init();
143
144 #[cfg(not(target_arch = "riscv64"))]
145 scheduler::add_current_core();
146 interrupts::enable();
147
148 kernel::boot_next_processor();
149
150 #[cfg(feature = "smp")]
151 synch_all_cores();
152
153 #[cfg(feature = "pci")]
154 drivers::pci::print_information();
155
156 unsafe { PerCoreScheduler::spawn(initd, 0, scheduler::task::NORMAL_PRIO, 0, USER_STACK_SIZE) };
158
159 PerCoreScheduler::run();
161}
162
163#[cfg(feature = "smp")]
165pub fn application_processor_main() -> ! {
166 kernel::application_processor_init();
167 #[cfg(not(target_arch = "riscv64"))]
168 scheduler::add_current_core();
169 interrupts::enable();
170 kernel::boot_next_processor();
171
172 debug!("Entering idle loop for application processor");
173
174 synch_all_cores();
175 executor::init();
176
177 PerCoreScheduler::run();
179}
180
181#[panic_handler]
182fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
183 let core_id = core_id();
184 panic_println!("[{core_id}][PANIC] {info}\n");
185
186 scheduler::shutdown(1);
187}