gila/src/kernel/main.rs
August 6882af0390
All checks were successful
Continuous Integration / Check (push) Successful in 46s
Continuous Integration / Clippy (push) Successful in 43s
Fix CS in IDT
2026-07-03 05:24:35 +00:00

241 lines
7.1 KiB
Rust

// 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 core::ptr::addr_of;
use arch::x86_64::interrupts::IDT;
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 limine::firmware::{
FIRMWARE_TYPE_EFI32, FIRMWARE_TYPE_EFI64, FIRMWARE_TYPE_SBI, FIRMWARE_TYPE_X86BIOS,
};
use spin::mutex::Mutex;
use x86_64::{VirtAddr, registers::rflags::RFlags, structures::idt::InterruptStackFrameValue};
use crate::{
arch::{
asm::ltr,
x86_64::{
cpuid::{CPUID, virt_supported},
gdt::SELECTORS,
},
},
boot::modules::MODULE_RESPONSE,
memory::paging::active_root_table,
};
lazy_static! {
pub static ref SERIAL_3F8: Mutex<SerialPort> = 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");
}
// END OF CRITICAL AREA
// Fallible code can be placed below this comment
// Initialize all statics so the bootloader memory can be reclaimed
memory::init_statics();
// Ensure IDT exists
SELECTORS.gdt.load();
log_info!("GDT loaded!");
IDT.load();
log_info!("IDT loaded!");
log_info!(
"Kernel cmdline: {}",
EXECUTABLE_FILE_RESPONSE.executable_file().cmdline()
);
log_info!(
"Kernel file path: {}",
EXECUTABLE_FILE_RESPONSE.executable_file().path()
);
let log_level = log::LOGGER.lock().level;
log_info!("Log level: {:?}", log_level);
// 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());
match boot::FIRMWARE_TYPE_REQUEST.response() {
Some(resp) => log_info!(
"Firmware type: {}",
match resp.firmware_type {
FIRMWARE_TYPE_SBI => "SBI",
FIRMWARE_TYPE_EFI32 => "UEFI (32-bit)",
FIRMWARE_TYPE_EFI64 => "UEFI (64-bit)",
FIRMWARE_TYPE_X86BIOS => "x86 BIOS",
_ => "Unknown",
}
),
None => log_warning!("Firmware type: No response"),
}
log_info!("Trans rights!");
if let Some(framebuffer_response) = FRAMEBUFFER_REQUEST.response() {
let fb = framebuffer_response.framebuffers_rev1().unwrap()[0];
log_info!("Framebuffer response received");
for mode in fb.modes() {
log_trace!(
"Mode: {}x{}, {} bits per pixel",
mode.width,
mode.height,
mode.bpp
);
}
} else {
log_info!("Framebuffer response absent, graphics disabled",);
}
let smp_response = MP_REQUEST.response();
match smp_response {
None => log_info!("Multiprocessing response not received"),
Some(resp) => {
log_info!("Multiprocessing response received");
log_info!("{} CPUs found", resp.cpus().len());
}
}
let rsdp_response = RSDP_REQUEST.response();
match rsdp_response {
None => log_info!("RDSP response not received"),
Some(resp) => {
log_info!("RSDP response received");
log_trace!("RSDP address: 0x{:x}", resp.address as usize)
}
}
boot::modules::log_modules();
memory::log_memory();
memory::log_address();
if let Some(string) = CPUID.get_processor_brand_string() {
log_info!("CPU brand string: {}", string.as_str());
}
if let Some(string) = CPUID.get_vendor_info() {
log_info!("CPU vendor: {}", string.as_str());
}
if let Some(string) = CPUID.get_hypervisor_info() {
log_info!("Hypervisor: {:?}", string.identify());
}
log_info!("Virtualization provider: {:?}", virt_supported());
{
let root_ptable_info = unsafe { active_root_table() };
log_info!(
"Root page table is Level {} at 0x{:x}",
root_ptable_info.1,
addr_of!(*root_ptable_info.0) as usize
);
// This is an expensive function. Only run it if we're actually logging the results.
//let loglevel = LOGGER.lock().level;
//if loglevel <= LogLevel::Trace {
// paging::walk_tables();
//}
}
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());
//let start_addr = VirtAddr::from_ptr(ub.data() as *const [u8]);
let start_addr = VirtAddr::from_ptr(usermode_fn as *const fn());
log_info!("Start address: 0x{:x}", start_addr);
x86_64::registers::model_specific::Star::write(
SELECTORS.sel_user_code,
SELECTORS.sel_user_stack,
SELECTORS.sel_kernel_code,
SELECTORS.sel_kernel_stack,
)
.expect("fuck");
ltr(SELECTORS.sel_tss.index());
unsafe {
InterruptStackFrameValue::new(
VirtAddr::from_ptr(usermode_fn as *const fn()),
SELECTORS.sel_user_code,
RFlags::INTERRUPT_FLAG,
VirtAddr::new(0xffffffff80000000),
SELECTORS.sel_user_stack,
)
.iretq();
}
}
// TODO:
// - Map APIC
// - Create an interrupt stack frame, push it to stack, and iret to userboot
panic!("Finished boot, but cannot start init because processes not implemented!");
}
fn usermode_fn() -> ! {
log_info!("In usermode!");
loop {
arch::asm::nop();
}
}