Skip to main content

hermit/
rt.rs

1use crate::arch::kernel;
2use crate::arch::kernel::core_local::{core_id, core_scheduler};
3use crate::arch::kernel::interrupts;
4use crate::scheduler::{PerCoreScheduler, PerCoreSchedulerExt};
5use crate::{console, drivers, env, executor, fs, logging, mm, scheduler, syscalls};
6
7mod built_info {
8	include!(concat!(env!("OUT_DIR"), "/built.rs"));
9}
10
11hermit_entry::define_abi_tag!();
12
13hermit_entry::define_entry_version!();
14
15#[cfg(test)]
16#[unsafe(no_mangle)]
17extern "C" fn runtime_entry(_argc: i32, _argv: *const *const u8, _env: *const *const u8) -> ! {
18	println!("Executing hermit unittests. Any arguments are dropped");
19	crate::test_main();
20	core_scheduler().exit(0)
21}
22
23//https://github.com/rust-lang/rust/issues/50297#issuecomment-524180479
24#[cfg(test)]
25pub fn test_runner(tests: &[&dyn Fn()]) {
26	println!("Running {} tests", tests.len());
27	for test in tests {
28		test();
29	}
30	core_scheduler().exit(0)
31}
32
33#[test_case]
34fn trivial_test() {
35	println!("Test test test");
36	panic!("Test called");
37}
38
39/// Entry point of a kernel thread, which initialize the libos
40extern "C" fn initd(_arg: usize) {
41	unsafe extern "C" {
42		#[cfg(all(not(test), not(any(feature = "nostd", feature = "common-os"))))]
43		fn runtime_entry(argc: i32, argv: *const *const u8, env: *const *const u8) -> !;
44		#[cfg(all(not(test), any(feature = "nostd", feature = "common-os")))]
45		fn main(argc: i32, argv: *const *const u8, env: *const *const u8);
46	}
47
48	// Initialize Drivers
49	drivers::init();
50	// The filesystem needs to be initialized before network to allow writing packet captures to a file.
51	fs::init();
52	executor::init();
53
54	syscalls::init();
55	#[cfg(feature = "shell")]
56	crate::shell::init();
57
58	// Get the application arguments and environment variables.
59	#[cfg(not(test))]
60	let (argc, argv, environ) = syscalls::get_application_parameters();
61
62	// give the IP thread time to initialize the network interface
63	core_scheduler().reschedule();
64
65	if cfg!(feature = "warn-prebuilt") {
66		warn!("This is a prebuilt Hermit kernel.");
67		warn!("For non-default device drivers and features, consider building a custom kernel.");
68	}
69
70	info!("Jumping into application");
71
72	#[cfg(not(test))]
73	unsafe {
74		// And finally start the application.
75		#[cfg(all(not(test), not(any(feature = "nostd", feature = "common-os"))))]
76		runtime_entry(argc, argv, environ);
77		#[cfg(all(not(test), any(feature = "nostd", feature = "common-os")))]
78		main(argc, argv, environ);
79	}
80	#[cfg(test)]
81	crate::test_main();
82}
83
84#[cfg(feature = "smp")]
85fn synch_all_cores() {
86	use core::hint;
87	use core::sync::atomic::{AtomicU32, Ordering};
88
89	static CORE_COUNTER: AtomicU32 = AtomicU32::new(0);
90
91	CORE_COUNTER.fetch_add(1, Ordering::SeqCst);
92
93	let possible_cpus = kernel::get_possible_cpus();
94	while CORE_COUNTER.load(Ordering::SeqCst) != possible_cpus {
95		hint::spin_loop();
96	}
97}
98
99/// Entry Point of Hermit for the Boot Processor
100pub fn boot_processor_main() -> ! {
101	use crate::config::USER_STACK_SIZE;
102
103	// Initialize the kernel and hardware.
104	mm::claim_initial_heap();
105	hermit_sync::Lazy::force(&console::CONSOLE);
106	env::init();
107	unsafe {
108		logging::init();
109	}
110
111	info!("Welcome to Hermit {}", env!("CARGO_PKG_VERSION"));
112	if let Some(git_version) = built_info::GIT_VERSION {
113		let dirty = if built_info::GIT_DIRTY == Some(true) {
114			" (dirty)"
115		} else {
116			""
117		};
118
119		let opt_level = if built_info::OPT_LEVEL == "3" {
120			format_args!("")
121		} else {
122			format_args!(" (opt-level={})", built_info::OPT_LEVEL)
123		};
124
125		info!("Git version: {git_version}{dirty}{opt_level}");
126	}
127	let arch = built_info::TARGET.split_once('-').unwrap().0;
128	info!("Architecture: {arch}");
129	info!("Enabled features: {}", built_info::FEATURES_LOWERCASE_STR);
130	info!("Built on {}", built_info::BUILT_TIME_UTC);
131
132	info!("Executable start: {:p}", elf_symbols::executable_start());
133	info!("ELF header:       {:p}", elf_symbols::elf_header());
134	info!("Text segment end: {:p}", elf_symbols::text_end());
135	info!("Data segment end: {:p}", elf_symbols::data_end());
136	info!("Executable end:   {:p}", elf_symbols::executable_end());
137
138	if let Some(fdt) = env::fdt() {
139		info!("FDT:\n{fdt:#?}");
140	}
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	// Start the initd task.
157	unsafe { PerCoreScheduler::spawn(initd, 0, scheduler::task::NORMAL_PRIO, 0, USER_STACK_SIZE) };
158
159	// Run the scheduler loop.
160	PerCoreScheduler::run();
161}
162
163/// Entry Point of Hermit for an Application Processor
164#[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	// Run the scheduler loop.
178	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}