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(implicit_provenance_casts)]
80
81#[macro_use]
83extern crate alloc;
84#[macro_use]
85extern crate bitflags;
86#[macro_use]
87extern crate log;
88#[cfg(not(target_os = "none"))]
89#[macro_use]
90extern crate std;
91
92#[cfg(feature = "smp")]
93use core::hint::spin_loop;
94#[cfg(feature = "smp")]
95use core::sync::atomic::{AtomicU32, Ordering};
96
97use self::arch::kernel;
98use self::arch::kernel::core_local::{core_id, core_scheduler};
99use self::arch::kernel::interrupts;
100use crate::scheduler::{PerCoreScheduler, PerCoreSchedulerExt};
101
102#[macro_use]
103mod macros;
104
105#[macro_use]
106mod logging;
107
108pub mod arch;
109#[cfg(all(feature = "common-os", target_arch = "x86_64"))]
110pub mod common_os;
111pub mod config;
112pub mod console;
113mod drivers;
114mod entropy;
115mod env;
116pub mod errno;
117mod executor;
118pub mod fd;
119pub mod fs;
120mod init_buf;
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;
130#[cfg(feature = "uhyve")]
131mod uhyve;
132
133mod built_info {
134 include!(concat!(env!("OUT_DIR"), "/built.rs"));
135}
136
137hermit_entry::define_abi_tag!();
138
139#[cfg(target_os = "none")]
140hermit_entry::define_entry_version!();
141
142#[cfg(test)]
143#[cfg(target_os = "none")]
144#[unsafe(no_mangle)]
145extern "C" fn runtime_entry(_argc: i32, _argv: *const *const u8, _env: *const *const u8) -> ! {
146 println!("Executing hermit unittests. Any arguments are dropped");
147 test_main();
148 core_scheduler().exit(0)
149}
150
151#[cfg(test)]
153pub fn test_runner(tests: &[&dyn Fn()]) {
154 println!("Running {} tests", tests.len());
155 for test in tests {
156 test();
157 }
158 core_scheduler().exit(0)
159}
160
161#[cfg(target_os = "none")]
162#[test_case]
163fn trivial_test() {
164 println!("Test test test");
165 panic!("Test called");
166}
167
168#[cfg(target_os = "none")]
170extern "C" fn initd(_arg: usize) {
171 unsafe extern "C" {
172 #[cfg(all(not(test), not(any(feature = "nostd", feature = "common-os"))))]
173 fn runtime_entry(argc: i32, argv: *const *const u8, env: *const *const u8) -> !;
174 #[cfg(all(not(test), any(feature = "nostd", feature = "common-os")))]
175 fn main(argc: i32, argv: *const *const u8, env: *const *const u8);
176 }
177
178 drivers::init();
180 fs::init();
182 executor::init();
183
184 syscalls::init();
185 #[cfg(feature = "shell")]
186 shell::init();
187
188 #[cfg(not(test))]
190 let (argc, argv, environ) = syscalls::get_application_parameters();
191
192 core_scheduler().reschedule();
194
195 if cfg!(feature = "warn-prebuilt") {
196 warn!("This is a prebuilt Hermit kernel.");
197 warn!("For non-default device drivers and features, consider building a custom kernel.");
198 }
199
200 info!("Jumping into application");
201
202 #[cfg(not(test))]
203 unsafe {
204 #[cfg(all(not(test), not(any(feature = "nostd", feature = "common-os"))))]
206 runtime_entry(argc, argv, environ);
207 #[cfg(all(not(test), any(feature = "nostd", feature = "common-os")))]
208 main(argc, argv, environ);
209 }
210 #[cfg(test)]
211 test_main();
212}
213
214#[cfg(feature = "smp")]
215fn synch_all_cores() {
216 static CORE_COUNTER: AtomicU32 = AtomicU32::new(0);
217
218 CORE_COUNTER.fetch_add(1, Ordering::SeqCst);
219
220 let possible_cpus = kernel::get_possible_cpus();
221 while CORE_COUNTER.load(Ordering::SeqCst) != possible_cpus {
222 spin_loop();
223 }
224}
225
226#[cfg(target_os = "none")]
228fn boot_processor_main() -> ! {
229 use crate::config::USER_STACK_SIZE;
230
231 mm::claim_initial_heap();
233 hermit_sync::Lazy::force(&console::CONSOLE);
234 env::init();
235 unsafe {
236 logging::init();
237 }
238
239 info!("Welcome to Hermit {}", env!("CARGO_PKG_VERSION"));
240 if let Some(git_version) = built_info::GIT_VERSION {
241 let dirty = if built_info::GIT_DIRTY == Some(true) {
242 " (dirty)"
243 } else {
244 ""
245 };
246
247 let opt_level = if built_info::OPT_LEVEL == "3" {
248 format_args!("")
249 } else {
250 format_args!(" (opt-level={})", built_info::OPT_LEVEL)
251 };
252
253 info!("Git version: {git_version}{dirty}{opt_level}");
254 }
255 let arch = built_info::TARGET.split_once('-').unwrap().0;
256 info!("Architecture: {arch}");
257 info!("Enabled features: {}", built_info::FEATURES_LOWERCASE_STR);
258 info!("Built on {}", built_info::BUILT_TIME_UTC);
259
260 info!("Executable start: {:p}", elf_symbols::executable_start());
261 info!("ELF header: {:p}", elf_symbols::elf_header());
262 info!("Text segment end: {:p}", elf_symbols::text_end());
263 info!("Data segment end: {:p}", elf_symbols::data_end());
264 info!("Executable end: {:p}", elf_symbols::executable_end());
265
266 if let Some(fdt) = env::fdt() {
267 info!("FDT:\n{fdt:#?}");
268 }
269
270 kernel::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 #[cfg(feature = "pci")]
282 drivers::pci::print_information();
283
284 unsafe { PerCoreScheduler::spawn(initd, 0, scheduler::task::NORMAL_PRIO, 0, USER_STACK_SIZE) };
286
287 PerCoreScheduler::run();
289}
290
291#[cfg(all(target_os = "none", feature = "smp"))]
293fn application_processor_main() -> ! {
294 kernel::application_processor_init();
295 #[cfg(not(target_arch = "riscv64"))]
296 scheduler::add_current_core();
297 interrupts::enable();
298 kernel::boot_next_processor();
299
300 debug!("Entering idle loop for application processor");
301
302 synch_all_cores();
303 executor::init();
304
305 PerCoreScheduler::run();
307}
308
309#[cfg(target_os = "none")]
310#[panic_handler]
311fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
312 let core_id = core_id();
313 panic_println!("[{core_id}][PANIC] {info}\n");
314
315 scheduler::shutdown(1);
316}