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