Skip to main content

kernel/
main.rs

1// SPDX-License-Identifier: GPL-3.0-only
2//! Kernel entry point and early-boot global state.
3//!
4//! Authors: MarioS271
5
6#![no_std]
7#![no_main]
8#![feature(abi_x86_interrupt)]
9
10extern crate alloc;
11
12mod types;
13mod panic;
14mod arch;
15mod logging;
16mod screen;
17mod mem;
18mod state;
19mod config;
20
21use spin::Once;
22use limine::request::{FramebufferRequest, HhdmRequest, MemmapRequest};
23use crate::arch::instructions;
24use crate::panic::kernel_panic;
25use crate::types::panic_codes::PanicCode;
26
27/// Early-boot singleton resources; written once in `kmain`, then read-only.
28///
29/// Kept separate from [`KState`] so the panic handler still has a reliable source
30/// of state if `KState` is unavailable.
31struct SimpleKernelState {
32    serial: Once<logging::serial::Serial>,
33    basic_fb: Once<screen::basic::framebuffer::BasicFramebuffer>,
34    basic_fb_psf2_font: Once<screen::basic::font::Psf2Font>,
35    pmm: Once<mem::pmm::Pmm>,
36    vmm: Once<mem::vmm::Vmm>,
37}
38
39/// Limine request for the linear framebuffer.
40static LIMINE_FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new();
41
42/// Limine request for the physical memory map.
43static LIMINE_MEMMAP_REQUEST: MemmapRequest = MemmapRequest::new();
44
45/// Limine request for the Higher-Half Direct Map (HHDM) offset.
46static LIMINE_HHDM_REQUEST: HhdmRequest = HhdmRequest::new();
47
48/// Global early-boot state, readable from anywhere in the kernel once initialized.
49pub(crate) static SIMPLE_STATE: SimpleKernelState = SimpleKernelState {
50    serial: Once::new(),
51    basic_fb: Once::new(),
52    basic_fb_psf2_font: Once::new(),
53    pmm: Once::new(),
54    vmm: Once::new(),
55};
56
57/// Kernel entry point called by the Limine bootloader; runs boot init and never returns.
58#[no_mangle]
59extern "C" fn kmain() -> ! {
60    {
61        use logging::serial::Serial;
62        use logging::_serial::{SerialPort, _Serial};
63
64        SIMPLE_STATE.serial.call_once(|| -> Serial {
65            Serial::new(SerialPort::Serial1)
66        });
67        let res = SIMPLE_STATE.serial.get().unwrap().init();
68        if !res.is_ok() {
69            kernel_panic(
70                PanicCode::InitFailure,
71                "Failed to initialize serial for kernel logging"
72            );
73        }
74    }
75
76    {
77        use crate::screen::basic::framebuffer::BasicFramebuffer;
78        use crate::screen::basic::font::Psf2Font;
79
80        if let Some(fb_response) = LIMINE_FRAMEBUFFER_REQUEST.response() {
81            if let Some(fb) = fb_response.framebuffers().first() {
82                SIMPLE_STATE.basic_fb.call_once(|| -> BasicFramebuffer {
83                    BasicFramebuffer::new(fb)
84                });
85                SIMPLE_STATE.basic_fb_psf2_font.call_once(|| -> Psf2Font {
86                    Psf2Font::init()
87                });
88            }
89        }
90    }
91
92    kinfo!("Hello, FerriteOS!");
93    kdebug!("Debug logging is active!");
94
95    // Init arch-specific features (GDT, IDT for x86_64, ...)
96    arch::init();
97
98    {
99        // Init physical + virtual mem manager
100        if let Some(memmap_response) = LIMINE_MEMMAP_REQUEST.response() {
101            if let Some(hhdm_response) = LIMINE_HHDM_REQUEST.response() {
102                SIMPLE_STATE.pmm.call_once(|| mem::pmm::Pmm::init(memmap_response.entries(), hhdm_response.offset) );
103                SIMPLE_STATE.vmm.call_once(|| mem::vmm::Vmm::init(SIMPLE_STATE.pmm.get().unwrap(), hhdm_response.offset));
104            }
105        }
106    }
107
108    // Init heap allocator
109    mem::heap::init(SIMPLE_STATE.pmm.get().unwrap(), SIMPLE_STATE.vmm.get().unwrap());
110
111    instructions::enable_interrupts();
112
113
114    kinfo!("Kernel ran successfully!");
115
116    // To halt the kernel on finish (temporary)
117    loop {
118        unsafe {
119            core::arch::asm!("hlt", options(nostack, nomem))
120        }
121    }
122}