1#![no_std]
2#![no_main]
3#![feature(abi_x86_interrupt)]
4#![feature(linked_list_cursors)]
5#![feature(btree_extract_if)]
6#![feature(custom_test_frameworks)]
7#![test_runner(crate::testing::test_runner)]
8#![reexport_test_harness_main = "test_main"]
9#![cfg_attr(test, allow(dead_code))]
11#![cfg_attr(test, allow(unused_imports))]
12
13extern crate alloc;
14
15core::arch::global_asm!(include_str!("boot.S"));
18
19#[macro_use]
20mod macros;
22
23mod acpi;
24mod cmdline;
25mod collections;
26mod cpu;
27mod devices;
28mod executable;
29mod fs;
30mod graphics;
31mod hw;
32mod io;
33mod memory_management;
34mod multiboot2;
35mod net;
36mod panic_handler;
37mod power;
38mod process;
39mod sync;
40mod testing;
41mod utils;
42
43use alloc::vec::Vec;
44use cpu::{
45 gdt,
46 interrupts::{self, apic},
47};
48use executable::elf::Elf;
49use increasing_heap_allocator::HeapStats;
50use io::console;
51use kernel_user_link::{
52 file::{BlockingMode, OpenOptions},
53 FD_STDERR, FD_STDIN, FD_STDOUT,
54};
55use memory_management::virtual_memory_mapper;
56use multiboot2::MultiBoot2Info;
57use process::scheduler;
58use tracing::{error, info};
59
60use crate::{
61 devices::clock,
62 memory_management::{
63 kernel_heap_allocator::ALLOCATOR,
64 memory_layout::{self, MemSize, KERNEL_HEAP_SIZE, PAGE_4K},
65 physical_page_allocator, virtual_space,
66 },
67 process::Process,
68};
69
70fn finish_boot() {
71 let physical_pages_stats = physical_page_allocator::stats();
72 let free_mem = MemSize(physical_pages_stats.0 * PAGE_4K);
73 let used_mem = MemSize(physical_pages_stats.1 * PAGE_4K);
74 let HeapStats {
77 allocated,
78 free_size,
79 heap_size,
80 } = ALLOCATOR.stats();
81 info!("Boot finished!");
82 memory_layout::display_kernel_map();
83 info!("Free memory: {}", free_mem);
84 info!(
85 "Used memory: {} ({:0.3}%)",
86 used_mem,
87 used_mem.0 as f64 / (used_mem.0 + free_mem.0) as f64 * 100.
88 );
89 info!("Free heap: {}", MemSize(free_size));
90 info!(
91 "Used heap: {} ({:0.3}%)",
92 MemSize(allocated),
93 allocated as f64 / heap_size as f64 * 100.
94 );
95 info!(
96 "From possible heap: {} ({:0.3}%)",
97 MemSize(KERNEL_HEAP_SIZE),
98 allocated as f64 / KERNEL_HEAP_SIZE as f64 * 100.
99 );
100 virtual_space::debug_blocks();
101 info!("");
102}
103
104fn load_init_process() {
105 let mut init_file = fs::File::open("/init").expect("Could not find `init` file");
106 let elf = Elf::load(&mut init_file).expect("Could not load init file");
107 let mut process = Process::allocate_process(
108 0,
109 &elf,
110 &mut init_file,
111 Vec::new(),
112 fs::Directory::open("/").expect("No root"),
113 )
114 .expect("Could not allocate process for `init`");
115 assert_eq!(process.id(), 0, "Must be the first process");
116
117 let mut console = fs::File::open_blocking(
120 "/devices/console",
121 BlockingMode::Line,
122 OpenOptions::READ | OpenOptions::WRITE,
123 )
124 .expect("Could not find `/devices/console`");
125 console.set_terminal(true);
127 process.attach_fs_node_to_fd(FD_STDIN, console.clone_inherit());
128 process.attach_fs_node_to_fd(FD_STDOUT, console.clone_inherit());
129 process.attach_fs_node_to_fd(FD_STDERR, console);
130
131 info!("Added `init` process pid={}", process.id());
132 scheduler::push_process(process);
133}
134
135#[link_section = ".text"]
136#[no_mangle]
137#[cfg(not(test))]
138pub extern "C" fn kernel_main(multiboot_info: &'static MultiBoot2Info) -> ! {
141 cmdline::init(multiboot_info);
143 console::early_init();
145 console::tracing::init();
146 cmdline::print_cmdline_parse(multiboot_info);
147 info!("{}", multiboot_info);
148 physical_page_allocator::init(multiboot_info);
150 virtual_memory_mapper::init_kernel_vm();
152 console::tracing::move_to_dynamic_buffer();
154 gdt::init_kernel_gdt();
156 interrupts::init_interrupts();
157 devices::init_devices_mapping();
159 let bios_tables = acpi::init_acpi_tables(multiboot_info);
160 info!("BIOS tables: {}", bios_tables);
161 apic::init(bios_tables);
162 acpi::init();
164 clock::init(bios_tables);
165
166 unsafe { cpu::set_interrupts() };
169 devices::init_legacy_devices();
170 graphics::vga::init(multiboot_info.framebuffer());
171 console::init_late_device(multiboot_info.framebuffer());
172 devices::probe_pci_devices();
173 let disk_load_success = match fs::create_disk_mapping(0) {
174 Ok(()) => true,
175 Err(e) => {
176 error!("Could not create disk mapping: {:?}", e);
177 false
178 }
179 };
180 finish_boot();
181 if disk_load_success {
184 load_init_process();
185 } else {
186 info!("No disk is available, so can't load `init` process, the system will just wait like this...");
187 }
188
189 scheduler::schedule();
191 power::finish_power_sequence();
193}
194
195#[link_section = ".text"]
196#[no_mangle]
197#[cfg(test)]
198pub extern "C" fn kernel_main(multiboot_info: &MultiBoot2Info) -> ! {
199 console::early_init();
201 physical_page_allocator::init(multiboot_info);
202 virtual_memory_mapper::init_kernel_vm();
203
204 test_main();
205
206 loop {
207 unsafe {
208 cpu::halt();
209 }
210 }
211}