1#![cfg_attr(
33 not(feature = "document-features"),
34 doc = "Activate the `document-features` Cargo feature to see feature docs here."
35)]
36#![cfg_attr(feature = "document-features", doc = document_features::document_features!())]
37#![allow(clippy::missing_safety_doc)]
42#![cfg_attr(
43 any(target_arch = "aarch64", target_arch = "riscv64"),
44 allow(incomplete_features)
45)]
46#![cfg_attr(target_arch = "x86_64", feature(abi_x86_interrupt))]
47#![feature(allocator_api)]
48#![cfg_attr(docsrs, feature(doc_cfg))]
49#![cfg_attr(
50 all(
51 not(any(feature = "common-os", feature = "nostd")),
52 not(target_arch = "riscv64"),
53 ),
54 feature(linkage)
55)]
56#![feature(linked_list_cursors)]
57#![feature(never_type)]
58#![cfg_attr(
59 any(target_arch = "aarch64", target_arch = "riscv64"),
60 feature(specialization)
61)]
62#![cfg_attr(
63 all(
64 not(any(feature = "common-os", feature = "nostd")),
65 not(target_arch = "riscv64"),
66 ),
67 feature(thread_local)
68)]
69#![cfg_attr(target_os = "none", no_std)]
70#![cfg_attr(target_os = "none", feature(custom_test_frameworks))]
71#![cfg_attr(all(target_os = "none", test), test_runner(crate::test_runner))]
72#![cfg_attr(
73 all(target_os = "none", test),
74 reexport_test_harness_main = "test_main"
75)]
76#![cfg_attr(all(target_os = "none", test), no_main)]
77#![feature(strict_provenance_lints)]
79#![warn(fuzzy_provenance_casts)]
80#![warn(lossy_provenance_casts)]
81
82#[macro_use]
84extern crate alloc;
85#[macro_use]
86extern crate bitflags;
87#[macro_use]
88extern crate log;
89#[cfg(not(target_os = "none"))]
90#[macro_use]
91extern crate std;
92
93#[cfg(feature = "smp")]
94use core::hint::spin_loop;
95#[cfg(feature = "smp")]
96use core::sync::atomic::{AtomicU32, Ordering};
97
98use arch::core_local::*;
99
100pub(crate) use crate::arch::*;
101pub use crate::config::DEFAULT_STACK_SIZE;
102pub(crate) use crate::config::*;
103use crate::scheduler::{PerCoreScheduler, PerCoreSchedulerExt};
104
105#[macro_use]
106mod macros;
107
108#[macro_use]
109mod logging;
110
111pub mod arch;
112mod config;
113pub mod console;
114mod drivers;
115mod entropy;
116mod env;
117pub mod errno;
118mod executor;
119pub mod fd;
120pub mod fs;
121mod init_cell;
122pub mod io;
123pub mod mm;
124pub mod scheduler;
125#[cfg(feature = "shell")]
126mod shell;
127mod synch;
128pub mod syscalls;
129pub mod time;
130mod uhyve;
131
132mod built_info {
133 include!(concat!(env!("OUT_DIR"), "/built.rs"));
134}
135
136hermit_entry::define_abi_tag!();
137
138#[cfg(target_os = "none")]
139hermit_entry::define_entry_version!();
140
141#[cfg(target_os = "none")]
142hermit_entry::define_uhyve_interface_version!(uhyve_interface::UHYVE_INTERFACE_VERSION);
143
144#[cfg(test)]
145#[cfg(target_os = "none")]
146#[unsafe(no_mangle)]
147extern "C" fn runtime_entry(_argc: i32, _argv: *const *const u8, _env: *const *const u8) -> ! {
148 println!("Executing hermit unittests. Any arguments are dropped");
149 test_main();
150 core_scheduler().exit(0)
151}
152
153#[cfg(test)]
155pub fn test_runner(tests: &[&dyn Fn()]) {
156 println!("Running {} tests", tests.len());
157 for test in tests {
158 test();
159 }
160 core_scheduler().exit(0)
161}
162
163#[cfg(target_os = "none")]
164#[test_case]
165fn trivial_test() {
166 println!("Test test test");
167 panic!("Test called");
168}
169
170#[cfg(target_os = "none")]
172extern "C" fn initd(_arg: usize) {
173 unsafe extern "C" {
174 #[cfg(all(not(test), not(any(feature = "nostd", feature = "common-os"))))]
175 fn runtime_entry(argc: i32, argv: *const *const u8, env: *const *const u8) -> !;
176 #[cfg(all(not(test), any(feature = "nostd", feature = "common-os")))]
177 fn main(argc: i32, argv: *const *const u8, env: *const *const u8);
178 }
179
180 if env::is_uhyve() {
181 info!("Hermit is running on uhyve!");
182 } else {
183 info!("Hermit is running on common system!");
184 }
185
186 drivers::init();
188 fs::init();
190 executor::init();
191
192 syscalls::init();
193 #[cfg(feature = "shell")]
194 shell::init();
195
196 #[cfg(not(test))]
198 let (argc, argv, environ) = syscalls::get_application_parameters();
199
200 core_scheduler().reschedule();
202
203 if cfg!(feature = "warn-prebuilt") {
204 warn!("This is a prebuilt Hermit kernel.");
205 warn!("For non-default device drivers and features, consider building a custom kernel.");
206 }
207
208 info!("Jumping into application");
209
210 #[cfg(not(test))]
211 unsafe {
212 #[cfg(all(not(test), not(any(feature = "nostd", feature = "common-os"))))]
214 runtime_entry(argc, argv, environ);
215 #[cfg(all(not(test), any(feature = "nostd", feature = "common-os")))]
216 main(argc, argv, environ);
217 }
218 #[cfg(test)]
219 test_main();
220}
221
222#[cfg(feature = "smp")]
223fn synch_all_cores() {
224 static CORE_COUNTER: AtomicU32 = AtomicU32::new(0);
225
226 CORE_COUNTER.fetch_add(1, Ordering::SeqCst);
227
228 let possible_cpus = kernel::get_possible_cpus();
229 while CORE_COUNTER.load(Ordering::SeqCst) != possible_cpus {
230 spin_loop();
231 }
232}
233
234#[cfg(target_os = "none")]
236fn boot_processor_main() -> ! {
237 hermit_sync::Lazy::force(&console::CONSOLE);
239 unsafe {
240 logging::init();
241 }
242
243 info!("Welcome to Hermit {}", env!("CARGO_PKG_VERSION"));
244 if let Some(git_version) = built_info::GIT_VERSION {
245 let dirty = if built_info::GIT_DIRTY == Some(true) {
246 " (dirty)"
247 } else {
248 ""
249 };
250
251 let opt_level = if built_info::OPT_LEVEL == "3" {
252 format_args!("")
253 } else {
254 format_args!(" (opt-level={})", built_info::OPT_LEVEL)
255 };
256
257 info!("Git version: {git_version}{dirty}{opt_level}");
258 }
259 let arch = built_info::TARGET.split_once('-').unwrap().0;
260 info!("Architecture: {arch}");
261 info!("Enabled features: {}", built_info::FEATURES_LOWERCASE_STR);
262 info!("Built on {}", built_info::BUILT_TIME_UTC);
263
264 env::log_segments();
265
266 if let Some(fdt) = env::fdt() {
267 info!("FDT:\n{fdt:#?}");
268 }
269
270 boot_processor_init();
271
272 #[cfg(not(target_arch = "riscv64"))]
273 scheduler::add_current_core();
274 interrupts::enable();
275
276 kernel::boot_next_processor();
277
278 #[cfg(feature = "smp")]
279 synch_all_cores();
280
281 if kernel::is_uhyve_with_pci() || !env::is_uhyve() {
282 #[cfg(feature = "pci")]
283 drivers::pci::print_information();
284 }
285
286 unsafe { PerCoreScheduler::spawn(initd, 0, scheduler::task::NORMAL_PRIO, 0, USER_STACK_SIZE) };
288
289 PerCoreScheduler::run();
291}
292
293#[cfg(all(target_os = "none", feature = "smp"))]
295fn application_processor_main() -> ! {
296 application_processor_init();
297 #[cfg(not(target_arch = "riscv64"))]
298 scheduler::add_current_core();
299 interrupts::enable();
300 kernel::boot_next_processor();
301
302 debug!("Entering idle loop for application processor");
303
304 synch_all_cores();
305 executor::init();
306
307 PerCoreScheduler::run();
309}
310
311#[cfg(target_os = "none")]
312#[panic_handler]
313fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
314 let core_id = core_id();
315 panic_println!("[{core_id}][PANIC] {info}\n");
316
317 scheduler::shutdown(1);
318}