Skip to main content

kernel/
main.rs

1// SPDX-License-Identifier: GPL-3.0-only
2//! Kernel entry point
3//!
4//! Authors: MarioS271
5
6#![no_std]
7#![no_main]
8#![feature(abi_x86_interrupt)]
9#![allow(special_module_name)]
10
11extern crate alloc;
12
13mod arch;
14mod cpu;
15mod drivers;
16mod ipc;
17mod kprint;
18mod lib;
19mod mm;
20mod net;
21mod sched;
22mod state;
23mod syscall;
24mod vfs;
25
26mod config;
27
28use crate::lib::addr::VirtAddr;
29use crate::lib::panic::kernel_panic;
30use crate::lib::panic_codes::PanicCode;
31use crate::lib::types::boot_info::{BootInfo, FramebufferInfo};
32use crate::sched::spawn::{SpawnError, spawn_from_elf};
33use crate::state::kstate::KSTATE;
34use crate::state::simple_state::SIMPLE_STATE;
35
36// Embedded User binary, only temporary
37#[repr(align(8))]
38struct AlignedBytes<const N: usize> {
39    bytes: [u8; N],
40}
41const USER_BINARY_LEN: usize = include_bytes!("../resources/user-binary").len();
42static USER_BINARY_ALIGNED: AlignedBytes<USER_BINARY_LEN> = AlignedBytes {
43    bytes: *include_bytes!("../resources/user-binary"),
44};
45pub static USER_BINARY: &[u8] = &USER_BINARY_ALIGNED.bytes;
46
47
48/// Abstract kernel entry point, called from the per-arch entry
49pub(crate) fn kernel_main(boot_info: BootInfo) -> ! {
50    // Stage 1
51    KSTATE.mm.set_hhdm_offset(boot_info.hhdm_offset);
52    KSTATE.kprint.config().set_max_log_level(boot_info.cmdline.log_level);
53    KSTATE.kprint.config().set_log_targets(boot_info.cmdline.log_targets);
54    SIMPLE_STATE.set_panic_action(boot_info.cmdline.panic_action);
55    
56    basic_fb_init(&boot_info.framebuffer);
57
58    kinfo!("Hello, Ferrite!");
59    kdebug!("Debug kprint is active!");
60
61    // Stage 2
62    // Safety:
63    // - This is called exactly once right here
64    // - No SMP/threading is currently active
65    // - No jump to userspace has been made yet
66    unsafe { arch::init(&boot_info) };
67    cpu::instructions::enable_interrupts();
68
69
70    // Safety: we are already past stage 2
71    let pid = match unsafe { spawn_from_elf(USER_BINARY, 0) } {
72        Ok(p) => p,
73        Err(e) => {
74            kernel_panic(
75                match e {
76                    SpawnError::OutOfMemory => PanicCode::OutOfMemory,
77                    SpawnError::InvalidBinary => PanicCode::NoWorkingInit,
78                    SpawnError::MappingCollision => PanicCode::MemoryMappingCollision
79                },
80                "Could not spawn the USER_BINARY process"
81            )
82        }
83    };
84    KSTATE.sched.set_active_pid(pid);
85
86    unsafe {
87        let (page_ptr, kernel_stack, rip, rsp) = KSTATE.sched.with_process(pid, |p| {
88            p.status = sched::process::ProcessStatus::Running;
89            (p.addr_space.page_ptr(), p.kernel_stack_top, p.regs.rip, p.regs.rsp)
90        }).unwrap_or_else(
91            || kernel_panic(
92                PanicCode::ProcessNotFound,
93                "Could not fetch process info from process map"
94            )
95        );
96
97        KSTATE.cpu.bsp_cpu_state().set_kernel_stack_top(kernel_stack);
98
99        cpu::userspace::initial_userspace_jump(
100            page_ptr.as_u64() - KSTATE.mm.hhdm_offset(),
101            rip,
102            VirtAddr::new(rsp)
103        );
104    }
105
106    #[allow(unreachable_code)]
107    {
108        kemerg!("Init process died or was killed, panic'ing");
109        kernel_panic(
110            PanicCode::InitProcessDied,
111            "The init process (PID 1) has died, aborting!"
112        );
113    }
114}
115
116/// Initializes the Basic Framebuffer
117fn basic_fb_init(fb: &FramebufferInfo) {
118    use crate::drivers::gpu::basic_fb::font::Psf2Font;
119    use crate::drivers::gpu::basic_fb::framebuffer::BasicFramebuffer;
120
121    // Safety: we are in a non-SMP/non-threading context
122    unsafe {
123        SIMPLE_STATE.init_basic_fb(BasicFramebuffer::new(fb));
124        SIMPLE_STATE.init_basic_fb_psf2_font(Psf2Font::init());
125    }
126}