1#![allow(clippy::missing_safety_doc)]
6#![cfg_attr(
7 any(target_arch = "aarch64", target_arch = "riscv64"),
8 allow(incomplete_features)
9)]
10#![cfg_attr(target_arch = "x86_64", feature(abi_x86_interrupt))]
11#![feature(allocator_api)]
12#![feature(linkage)]
13#![feature(linked_list_cursors)]
14#![feature(maybe_uninit_as_bytes)]
15#![feature(maybe_uninit_slice)]
16#![feature(maybe_uninit_write_slice)]
17#![feature(never_type)]
18#![feature(slice_from_ptr_range)]
19#![feature(slice_ptr_get)]
20#![cfg_attr(
21 any(target_arch = "aarch64", target_arch = "riscv64"),
22 feature(specialization)
23)]
24#![feature(thread_local)]
25#![cfg_attr(target_os = "none", no_std)]
26#![cfg_attr(target_os = "none", feature(custom_test_frameworks))]
27#![cfg_attr(all(target_os = "none", test), test_runner(crate::test_runner))]
28#![cfg_attr(
29 all(target_os = "none", test),
30 reexport_test_harness_main = "test_main"
31)]
32#![cfg_attr(all(target_os = "none", test), no_main)]
33
34#[macro_use]
36extern crate alloc;
37#[macro_use]
38extern crate bitflags;
39#[macro_use]
40extern crate log;
41#[cfg(not(target_os = "none"))]
42#[macro_use]
43extern crate std;
44
45#[cfg(feature = "smp")]
46use core::hint::spin_loop;
47#[cfg(feature = "smp")]
48use core::sync::atomic::{AtomicU32, Ordering};
49
50use arch::core_local::*;
51
52pub(crate) use crate::arch::*;
53pub use crate::config::DEFAULT_STACK_SIZE;
54pub(crate) use crate::config::*;
55pub use crate::fs::create_file;
56use crate::kernel::is_uhyve_with_pci;
57use crate::scheduler::{PerCoreScheduler, PerCoreSchedulerExt};
58
59#[macro_use]
60mod macros;
61
62#[macro_use]
63mod logging;
64
65pub mod arch;
66mod config;
67pub mod console;
68mod drivers;
69mod entropy;
70mod env;
71pub mod errno;
72mod executor;
73pub mod fd;
74pub mod fs;
75mod init_cell;
76pub mod io;
77pub mod mm;
78pub mod scheduler;
79#[cfg(feature = "shell")]
80mod shell;
81mod synch;
82pub mod syscalls;
83pub mod time;
84
85mod built_info {
86 include!(concat!(env!("OUT_DIR"), "/built.rs"));
87}
88
89hermit_entry::define_abi_tag!();
90
91#[cfg(target_os = "none")]
92hermit_entry::define_entry_version!();
93
94#[cfg(test)]
95#[cfg(target_os = "none")]
96#[unsafe(no_mangle)]
97extern "C" fn runtime_entry(_argc: i32, _argv: *const *const u8, _env: *const *const u8) -> ! {
98 println!("Executing hermit unittests. Any arguments are dropped");
99 test_main();
100 core_scheduler().exit(0)
101}
102
103#[cfg(test)]
105pub fn test_runner(tests: &[&dyn Fn()]) {
106 println!("Running {} tests", tests.len());
107 for test in tests {
108 test();
109 }
110 core_scheduler().exit(0)
111}
112
113#[cfg(target_os = "none")]
114#[test_case]
115fn trivial_test() {
116 println!("Test test test");
117 panic!("Test called");
118}
119
120#[cfg(target_os = "none")]
122extern "C" fn initd(_arg: usize) {
123 unsafe extern "C" {
124 #[cfg(all(not(test), not(any(feature = "nostd", feature = "common-os"))))]
125 fn runtime_entry(argc: i32, argv: *const *const u8, env: *const *const u8) -> !;
126 #[cfg(all(not(test), any(feature = "nostd", feature = "common-os")))]
127 fn main(argc: i32, argv: *const *const u8, env: *const *const u8);
128 }
129
130 if env::is_uhyve() {
131 info!("Hermit is running on uhyve!");
132 } else {
133 info!("Hermit is running on common system!");
134 }
135
136 drivers::init();
138 crate::executor::init();
139
140 syscalls::init();
141 fs::init();
142 #[cfg(feature = "shell")]
143 shell::init();
144
145 #[cfg(not(test))]
147 let (argc, argv, environ) = syscalls::get_application_parameters();
148
149 core_scheduler().reschedule();
151
152 info!("Jumping into application");
153
154 #[cfg(not(test))]
155 unsafe {
156 #[cfg(all(not(test), not(any(feature = "nostd", feature = "common-os"))))]
158 runtime_entry(argc, argv, environ);
159 #[cfg(all(not(test), any(feature = "nostd", feature = "common-os")))]
160 main(argc, argv, environ);
161 }
162 #[cfg(test)]
163 test_main();
164}
165
166#[cfg(feature = "smp")]
167fn synch_all_cores() {
168 static CORE_COUNTER: AtomicU32 = AtomicU32::new(0);
169
170 CORE_COUNTER.fetch_add(1, Ordering::SeqCst);
171
172 let possible_cpus = kernel::get_possible_cpus();
173 while CORE_COUNTER.load(Ordering::SeqCst) != possible_cpus {
174 spin_loop();
175 }
176}
177
178#[cfg(target_os = "none")]
180fn boot_processor_main() -> ! {
181 hermit_sync::Lazy::force(&console::CONSOLE);
183 unsafe {
184 logging::init();
185 }
186
187 info!("Welcome to Hermit {}", env!("CARGO_PKG_VERSION"));
188 if let Some(git_version) = built_info::GIT_VERSION {
189 let dirty = if built_info::GIT_DIRTY == Some(true) {
190 " (dirty)"
191 } else {
192 ""
193 };
194
195 let opt_level = if built_info::OPT_LEVEL == "3" {
196 format_args!("")
197 } else {
198 format_args!(" (opt-level={})", built_info::OPT_LEVEL)
199 };
200
201 info!("Git version: {git_version}{dirty}{opt_level}");
202 }
203 info!("Enabled features: {}", built_info::FEATURES_LOWERCASE_STR);
204 info!("Built on {}", built_info::BUILT_TIME_UTC);
205
206 info!("Kernel starts at {:p}", env::get_base_address());
207
208 if let Some(fdt) = env::fdt() {
209 info!("FDT:\n{fdt:#?}");
210 }
211
212 unsafe extern "C" {
213 static mut __bss_start: u8;
214 }
215 let bss_ptr = core::ptr::addr_of_mut!(__bss_start);
216 info!("BSS starts at {bss_ptr:p}");
217 info!("tls_info = {:#x?}", env::boot_info().load_info.tls_info);
218 arch::boot_processor_init();
219
220 #[cfg(not(target_arch = "riscv64"))]
221 scheduler::add_current_core();
222 interrupts::enable();
223
224 arch::kernel::boot_next_processor();
225
226 #[cfg(feature = "smp")]
227 synch_all_cores();
228
229 #[cfg(feature = "pci")]
230 info!("Compiled with PCI support");
231 #[cfg(all(feature = "acpi", target_arch = "x86_64"))]
232 info!("Compiled with ACPI support");
233 #[cfg(all(feature = "fsgsbase", target_arch = "x86_64"))]
234 info!("Compiled with FSGSBASE support");
235 #[cfg(feature = "smp")]
236 info!("Compiled with SMP support");
237
238 if is_uhyve_with_pci() || !env::is_uhyve() {
239 #[cfg(feature = "pci")]
240 crate::drivers::pci::print_information();
241 }
242
243 unsafe {
245 scheduler::PerCoreScheduler::spawn(
246 initd,
247 0,
248 scheduler::task::NORMAL_PRIO,
249 0,
250 USER_STACK_SIZE,
251 )
252 };
253
254 PerCoreScheduler::run();
256}
257
258#[cfg(all(target_os = "none", feature = "smp"))]
260fn application_processor_main() -> ! {
261 arch::application_processor_init();
262 #[cfg(not(target_arch = "riscv64"))]
263 scheduler::add_current_core();
264 interrupts::enable();
265 arch::kernel::boot_next_processor();
266
267 debug!("Entering idle loop for application processor");
268
269 synch_all_cores();
270 crate::executor::init();
271
272 PerCoreScheduler::run();
274}
275
276#[cfg(target_os = "none")]
277#[panic_handler]
278fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
279 let core_id = crate::arch::core_local::core_id();
280 panic_println!("[{core_id}][PANIC] {info}\n");
281
282 crate::scheduler::shutdown(1);
283}