// Copyright (c) 2025 shibedrill // SPDX-License-Identifier: MIT #![no_std] #![no_main] #![feature(abi_x86_interrupt)] mod arch; mod boot; mod constants; mod interrupt; #[macro_use] mod log; mod memory; mod panic; mod process; mod util; use arch::x86_64::serial::SerialPort; use boot::{BASE_REVISION, params}; use constants::*; use log::*; use memory::alloc::{boxed::Box, format, vec}; use params::*; use lazy_static::lazy_static; use spin::mutex::Mutex; use x86_64::VirtAddr; use crate::{arch::x86_64::gdt::SELECTORS, boot::modules::MODULE_RESPONSE}; lazy_static! { pub static ref SERIAL_3F8: Mutex = Mutex::new( arch::x86_64::serial::SerialPort::try_from_port(0x3f8).expect("Could not create port") ); } #[unsafe(no_mangle)] unsafe extern "C" fn main() -> ! { // CRITICAL AREA // Nothing non-essential should be done until we can initialize logging // Otherwise it will fail silently // 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.lock().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 let serial_logger = |msg: &str| SERIAL_3F8.lock().log_writeln(msg); LOGGER.lock().add_device(Box::new(serial_logger)); } log_trace!("Configured kernel logging devices"); let log_level = LOGGER.lock().level; log_info!("Log level: {:?}", log_level); } // END OF CRITICAL AREA // Fallible code can be placed below this comment let _ = arch::startup::init(); // Initialize all statics so the bootloader memory can be reclaimed memory::init_statics(); log_info!( "Boot cmdline: {} {}", EXECUTABLE_FILE_RESPONSE.executable_file().path(), EXECUTABLE_FILE_RESPONSE.executable_file().cmdline() ); // Branding for line in ASCII_LOGO { let mut locked = SERIAL_3F8.lock(); locked.log_write("\t\t"); locked.log_writeln(line); } SERIAL_3F8 .lock() .log_writeln("\tWelcome to the Gila microkernel!\n"); log_info!("Booting gila version {}", kernel_version_string()); log_info!("Trans rights!"); boot::modules::log_modules(); memory::log_memory(); memory::log_address(); log_info!( "TSS descriptor: 0x{:08x} {:08x}", SELECTORS.gdt.entries()[SELECTORS.sel_tss.index() as usize + 1].raw(), SELECTORS.gdt.entries()[SELECTORS.sel_tss.index() as usize].raw() ); if let Some(modules_list) = *MODULE_RESPONSE && modules_list.modules()[0].path().ends_with("/userboot.bin") { let ub = modules_list.modules()[0]; log_info!("Found userboot: {} {}", ub.path(), ub.cmdline()); // TODO: remap userboot as user pages let start_addr = VirtAddr::from_ptr(ub.data() as *const [u8]); log_trace!("Userboot start address: 0x{:x}", start_addr); arch::startup::jump_to_usermode(VirtAddr::new(0xffffffff80000000), start_addr) } else { panic!("Userboot not found, cannot boot!"); } }