// Copyright (c) 2025 shibedrill // SPDX-License-Identifier: GPL-3.0-or-later #![no_std] #![no_main] #![feature(cfg_match)] #![feature(allocator_api)] mod arch; mod boot; mod constants; mod device; #[macro_use] mod log; mod memory; mod panic; mod params; mod process; mod resources; #[cfg(target_arch = "x86_64")] use arch::x86_64::gdt; #[cfg(target_arch = "x86_64")] use arch::x86_64::serial::Serialport; use boot::*; use constants::*; use log::*; use memory::alloc::{format, string::*, vec}; use params::*; use limine::file::File; use limine::memory_map::EntryType; #[allow(unused_imports)] use lzma_rs::lzma_decompress; #[unsafe(no_mangle)] unsafe extern "C" fn main() -> ! { // Assert supported bootloader version assert!(BASE_REVISION.is_supported()); // Set up logging level from params // Nothing we can do here if this fails since no log subscribers are initialized yet if let Some(level) = PARAMS.get("-loglevel") && let Ok(parsed_level) = LogLevel::try_from(level.as_str()) { LOGGER.set_level(parsed_level); } // Add subscribers to logger if let Some(device) = PARAMS.get("-logdev") { let log_device_list: vec::Vec<&str> = device.split(',').collect(); if log_device_list.contains(&"display") { // Append display console to log subs } if log_device_list.contains(&"serial") { // TODO: Set up device discovery #[cfg(target_arch = "x86_64")] LOGGER.add_subscriber(Serialport::new(0x3f8)); } log_trace!("Boot: Configured kernel logging devices"); } log_info!( "Boot: Kernel cmdline: {}", String::from_utf8_lossy( limine::file::File::string(EXECUTABLE_FILE_RESPONSE.file()).to_bytes() ) ); log_info!( "Boot: Kernel file path: {}", String::from_utf8_lossy(EXECUTABLE_FILE_RESPONSE.file().path().to_bytes()) ); log_info!("Boot: Booting gila version {}", kernel_version_string()); log_info!("Boot: Trans rights!"); device::init_statics(); if let Some(framebuffer_response) = FRAMEBUFFER_REQUEST.get_response() { let fb = framebuffer_response.framebuffers().next().unwrap(); log_info!("Boot: Framebuffer response received"); log_trace!( "Boot: Framebuffer dimensions: {}x{}, {} bits per pixel", fb.width(), fb.height(), fb.bpp() ); } else { log_info!("Boot: Framebuffer response absent, graphics disabled",); } let smp_response = MP_REQUEST.get_response(); match smp_response { None => log_info!("MP: Multiprocessing response not received"), Some(resp) => { log_info!("MP: Multiprocessing response received"); log_trace!("MP: {} CPUs found", resp.cpus().len()); } } let module_response = MODULE_REQUEST .get_response() .expect("Bootloader did not return kernel modules"); log_info!( "Boot: {} kernel modules found", module_response.modules().len() ); if !module_response.modules().is_empty() { let mut log_msg: String = String::from("Boot: Kernel modules list:\n"); for module in module_response.modules() { log_msg.push_str(&format!( "\t\t{}", String::from_utf8_lossy(module.path().to_bytes()) )); } log_trace!("{log_msg}") } let irfs_path = { if let Some(key) = PARAMS.get("-initramfs") { key } else { INITRAMFS_DEFAULT_PATH } }; log_trace!("Boot: initramfs path requested: {irfs_path}"); let _initramfs = { let mut result: Option<&File> = None; for file in module_response.modules() { if file.path().to_string_lossy() == irfs_path { result = Some(file); log_info!("Boot: initramfs found"); } } result } .expect("initramfs not found in modules list"); // Panic if this is absent. It's needed to set up the GDT and paging let mmap_response = MEMMAP_REQUEST.get_response().expect("Bootloader did not supply memory map"); log_info!("Boot: Memory map received"); if !mmap_response.entries().is_empty() { let mut log_msg: String = String::from("Boot: Memory map:"); let mut usable: u64 = 0; let mut reclaimable: u64 = 0; let mut hardware: u64 = 0; let mut unusable: u64 = 0; for entry in mmap_response.entries() { log_msg.push_str(&format!( "\n\t\t0x{:x} bytes @ 0x{:x}: {}", entry.length, entry.base, match entry.entry_type { EntryType::ACPI_NVS => { hardware += entry.length; "ACPI (reserved)" } EntryType::ACPI_RECLAIMABLE => { reclaimable += entry.length; "ACPI (reclaimable)" } EntryType::BAD_MEMORY => { unusable += entry.length; "damaged/unusable" } EntryType::BOOTLOADER_RECLAIMABLE => { reclaimable += entry.length; "bootloader (reclaimable)" } #[allow(unreachable_patterns, deprecated)] EntryType::EXECUTABLE_AND_MODULES | EntryType::KERNEL_AND_MODULES => { unusable += entry.length; "executable & modules" } EntryType::FRAMEBUFFER => { hardware += entry.length; "framebuffer" } EntryType::RESERVED => { unusable += entry.length; "reserved" } EntryType::USABLE => { usable += entry.length; "usable" } _ => "unidentified", } )); } log_trace!("{log_msg}"); let total = usable + reclaimable + hardware + unusable; log_info!( "Boot: Memory report:\n\t\tFree: {usable}\n\t\tAvailable: {reclaimable}\n\t\tUsable: {}\n\t\tHardware: {hardware}\n\t\tUnusable: {unusable}\n\t\tTotal: {}", usable + reclaimable, total ); } else { panic!("Memory map contains no entries"); } #[cfg(target_arch = "x86_64")] gdt::setup_gdt(); #[allow(unreachable_code)] loop { for _i in 0..50000000u64 { unsafe { core::arch::asm!("nop"); } } core::hint::black_box(()); log_trace!("Heartbeat"); } }