hermit/
lib.rs

1//! First version is derived and adapted for Hermit from
2//! Philipp Oppermann's excellent series of blog posts (<http://blog.phil-opp.com/>)
3//! and Eric Kidd's toy OS (<https://github.com/emk/toyos-rs>).
4
5#![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(never_type)]
16#![feature(slice_from_ptr_range)]
17#![feature(slice_ptr_get)]
18#![cfg_attr(
19	any(target_arch = "aarch64", target_arch = "riscv64"),
20	feature(specialization)
21)]
22#![feature(thread_local)]
23#![cfg_attr(target_os = "none", no_std)]
24#![cfg_attr(target_os = "none", feature(custom_test_frameworks))]
25#![cfg_attr(all(target_os = "none", test), test_runner(crate::test_runner))]
26#![cfg_attr(
27	all(target_os = "none", test),
28	reexport_test_harness_main = "test_main"
29)]
30#![cfg_attr(all(target_os = "none", test), no_main)]
31// FIXME: move this to `Cargo.toml` once stable
32#![feature(strict_provenance_lints)]
33#![warn(fuzzy_provenance_casts)]
34#![warn(lossy_provenance_casts)]
35
36// EXTERNAL CRATES
37#[macro_use]
38extern crate alloc;
39#[macro_use]
40extern crate bitflags;
41#[macro_use]
42extern crate log;
43#[cfg(not(target_os = "none"))]
44#[macro_use]
45extern crate std;
46
47#[cfg(feature = "smp")]
48use core::hint::spin_loop;
49#[cfg(feature = "smp")]
50use core::sync::atomic::{AtomicU32, Ordering};
51
52use arch::core_local::*;
53
54pub(crate) use crate::arch::*;
55pub use crate::config::DEFAULT_STACK_SIZE;
56pub(crate) use crate::config::*;
57pub use crate::fs::create_file;
58use crate::scheduler::{PerCoreScheduler, PerCoreSchedulerExt};
59
60#[macro_use]
61mod macros;
62
63#[macro_use]
64mod logging;
65
66pub mod arch;
67mod config;
68pub mod console;
69mod drivers;
70mod entropy;
71mod env;
72pub mod errno;
73mod executor;
74pub mod fd;
75pub mod fs;
76mod init_cell;
77pub mod io;
78pub mod mm;
79pub mod scheduler;
80#[cfg(feature = "shell")]
81mod shell;
82mod synch;
83pub mod syscalls;
84pub mod time;
85
86mod built_info {
87	include!(concat!(env!("OUT_DIR"), "/built.rs"));
88}
89
90hermit_entry::define_abi_tag!();
91
92#[cfg(target_os = "none")]
93hermit_entry::define_entry_version!();
94
95#[cfg(target_os = "none")]
96hermit_entry::define_uhyve_interface_version!(uhyve_interface::UHYVE_INTERFACE_VERSION);
97
98#[cfg(test)]
99#[cfg(target_os = "none")]
100#[unsafe(no_mangle)]
101extern "C" fn runtime_entry(_argc: i32, _argv: *const *const u8, _env: *const *const u8) -> ! {
102	println!("Executing hermit unittests. Any arguments are dropped");
103	test_main();
104	core_scheduler().exit(0)
105}
106
107//https://github.com/rust-lang/rust/issues/50297#issuecomment-524180479
108#[cfg(test)]
109pub fn test_runner(tests: &[&dyn Fn()]) {
110	println!("Running {} tests", tests.len());
111	for test in tests {
112		test();
113	}
114	core_scheduler().exit(0)
115}
116
117#[cfg(target_os = "none")]
118#[test_case]
119fn trivial_test() {
120	println!("Test test test");
121	panic!("Test called");
122}
123
124/// Entry point of a kernel thread, which initialize the libos
125#[cfg(target_os = "none")]
126extern "C" fn initd(_arg: usize) {
127	unsafe extern "C" {
128		#[cfg(all(not(test), not(any(feature = "nostd", feature = "common-os"))))]
129		fn runtime_entry(argc: i32, argv: *const *const u8, env: *const *const u8) -> !;
130		#[cfg(all(not(test), any(feature = "nostd", feature = "common-os")))]
131		fn main(argc: i32, argv: *const *const u8, env: *const *const u8);
132	}
133
134	if env::is_uhyve() {
135		info!("Hermit is running on uhyve!");
136	} else {
137		info!("Hermit is running on common system!");
138	}
139
140	// Initialize Drivers
141	drivers::init();
142	crate::executor::init();
143
144	syscalls::init();
145	fs::init();
146	#[cfg(feature = "shell")]
147	shell::init();
148
149	// Get the application arguments and environment variables.
150	#[cfg(not(test))]
151	let (argc, argv, environ) = syscalls::get_application_parameters();
152
153	// give the IP thread time to initialize the network interface
154	core_scheduler().reschedule();
155
156	if cfg!(feature = "warn-prebuilt") {
157		warn!("This is a prebuilt Hermit kernel.");
158		warn!("For non-default device drivers and features, consider building a custom kernel.");
159	}
160
161	info!("Jumping into application");
162
163	#[cfg(not(test))]
164	unsafe {
165		// And finally start the application.
166		#[cfg(all(not(test), not(any(feature = "nostd", feature = "common-os"))))]
167		runtime_entry(argc, argv, environ);
168		#[cfg(all(not(test), any(feature = "nostd", feature = "common-os")))]
169		main(argc, argv, environ);
170	}
171	#[cfg(test)]
172	test_main();
173}
174
175#[cfg(feature = "smp")]
176fn synch_all_cores() {
177	static CORE_COUNTER: AtomicU32 = AtomicU32::new(0);
178
179	CORE_COUNTER.fetch_add(1, Ordering::SeqCst);
180
181	let possible_cpus = kernel::get_possible_cpus();
182	while CORE_COUNTER.load(Ordering::SeqCst) != possible_cpus {
183		spin_loop();
184	}
185}
186
187/// Entry Point of Hermit for the Boot Processor
188#[cfg(target_os = "none")]
189fn boot_processor_main() -> ! {
190	// Initialize the kernel and hardware.
191	hermit_sync::Lazy::force(&console::CONSOLE);
192	unsafe {
193		logging::init();
194	}
195
196	info!("Welcome to Hermit {}", env!("CARGO_PKG_VERSION"));
197	if let Some(git_version) = built_info::GIT_VERSION {
198		let dirty = if built_info::GIT_DIRTY == Some(true) {
199			" (dirty)"
200		} else {
201			""
202		};
203
204		let opt_level = if built_info::OPT_LEVEL == "3" {
205			format_args!("")
206		} else {
207			format_args!(" (opt-level={})", built_info::OPT_LEVEL)
208		};
209
210		info!("Git version: {git_version}{dirty}{opt_level}");
211	}
212	info!("Enabled features: {}", built_info::FEATURES_LOWERCASE_STR);
213	info!("Built on {}", built_info::BUILT_TIME_UTC);
214
215	info!("Kernel starts at {:p}", env::get_base_address());
216
217	if let Some(fdt) = env::fdt() {
218		info!("FDT:\n{fdt:#?}");
219	}
220
221	unsafe extern "C" {
222		static mut __bss_start: u8;
223	}
224	let bss_ptr = &raw mut __bss_start;
225	info!("BSS starts at {bss_ptr:p}");
226	info!("tls_info = {:#x?}", env::boot_info().load_info.tls_info);
227	arch::boot_processor_init();
228
229	#[cfg(not(target_arch = "riscv64"))]
230	scheduler::add_current_core();
231	interrupts::enable();
232
233	arch::kernel::boot_next_processor();
234
235	#[cfg(feature = "smp")]
236	synch_all_cores();
237
238	#[cfg(feature = "pci")]
239	info!("Compiled with PCI support");
240	#[cfg(all(feature = "acpi", target_arch = "x86_64"))]
241	info!("Compiled with ACPI support");
242	#[cfg(all(feature = "fsgsbase", target_arch = "x86_64"))]
243	info!("Compiled with FSGSBASE support");
244	#[cfg(feature = "smp")]
245	info!("Compiled with SMP support");
246
247	if kernel::is_uhyve_with_pci() || !env::is_uhyve() {
248		#[cfg(feature = "pci")]
249		crate::drivers::pci::print_information();
250	}
251
252	// Start the initd task.
253	unsafe {
254		scheduler::PerCoreScheduler::spawn(
255			initd,
256			0,
257			scheduler::task::NORMAL_PRIO,
258			0,
259			USER_STACK_SIZE,
260		)
261	};
262
263	// Run the scheduler loop.
264	PerCoreScheduler::run();
265}
266
267/// Entry Point of Hermit for an Application Processor
268#[cfg(all(target_os = "none", feature = "smp"))]
269fn application_processor_main() -> ! {
270	arch::application_processor_init();
271	#[cfg(not(target_arch = "riscv64"))]
272	scheduler::add_current_core();
273	interrupts::enable();
274	arch::kernel::boot_next_processor();
275
276	debug!("Entering idle loop for application processor");
277
278	synch_all_cores();
279	crate::executor::init();
280
281	// Run the scheduler loop.
282	PerCoreScheduler::run();
283}
284
285#[cfg(target_os = "none")]
286#[panic_handler]
287fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
288	let core_id = crate::arch::core_local::core_id();
289	panic_println!("[{core_id}][PANIC] {info}\n");
290
291	crate::scheduler::shutdown(1);
292}