216 lines
6.8 KiB
Rust
216 lines
6.8 KiB
Rust
// 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");
|
|
}
|
|
}
|