#![no_std] #![feature(abi_x86_interrupt, breakpoint)] #![warn( clippy::correctness, clippy::nursery, clippy::unnecessary_cast, clippy::all, clippy::suspicious, clippy::perf, rustdoc::missing_errors_doc, rustdoc::missing_panics_doc )] extern crate alloc; use crate::{ arch::x86_64::{ // cpu::apic::enable_apic, drivers::{ ascii::screensize_chars, framebuffer::display::screensize_px, }, gdt, interrupts, memory::{ FRAME_ALLOCATOR, allocation::{ heap_alloc::init_heap, page_alloc::FoundryOSFrameAllocator, }, init_page_table, mapping, units::MemoryUnits, }, }, prelude::*, }; use alloc::{boxed::Box, format}; use core::arch::asm; use limine::BaseRevision; use x86_64::VirtAddr; pub mod arch; /// Commonly used re-exports. pub mod prelude; pub mod resources; // We aren't using much of this right now. #[allow(unused)] pub mod std; mod step; pub mod util; /// Sets the base revision to the latest revision supported by the crate. /// See specification for further info. /// Be sure to mark all limine requests with #[used], otherwise they may be /// removed by the compiler. #[used] // The .requests section allows limine to find the requests faster and more // safely. #[unsafe(link_section = ".requests")] static BASE_REVISION: BaseRevision = BaseRevision::new(); pub fn hcf() -> ! { loop { unsafe { #[cfg(target_arch = "x86_64")] asm!("hlt"); } } } #[derive(Debug)] pub struct NoError {} impl core::fmt::Display for NoError { fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { Ok(()) } } pub struct NoTags; impl core::error::Error for NoError {} /// Panicking before this is initialised is unwise. We should probably extract /// very early init into it's own function because Stack Traces may require /// allocations etc. #[inline(never)] pub fn boot() -> Result<(), Box> { if !BASE_REVISION.is_supported() { return Err("Base revision not supported.".into()); } let memory_map = mapping::get_memory_map(); print_log!(" Initialising Serial... "); let res = arch::x86_64::drivers::serial::init(); serial_print!(" Initialising Serial... "); if res.is_err() { debugln!("[Not Detected]") } else { debugln!("[Success]"); } debugln!( "Display is {:?} chars, {:?} px.", screensize_chars(), screensize_px() ); debug!(" Setting Up Global Descriptor Table... "); gdt::init(); debugln!("[Success]"); debug!(" Setting Up Interrupt Descriptor Table... "); interrupts::init_idt(); debugln!("[Success]"); debugln!(" Initialising Memory Subsystem... "); let physical_memory_offset = VirtAddr::new(*mapping::PHYSICAL_MEMORY_OFFSET); init_page_table(physical_memory_offset); FoundryOSFrameAllocator::init(memory_map); let available_bytes = FRAME_ALLOCATOR.get().unwrap().lock().available_memory(); debugln!( " => Available Memory: {}", MemoryUnits::from_bytes(available_bytes as usize) ); // Allocations should be all fine past this point. debugln!(" Initialising Heap... "); match unsafe { init_heap() } { Ok(_) => debugln!(" [Success]"), Err(why) => return Err(format!("{:?}", why).into()), } debug!(" Enabling PICs... "); interrupts::enable_pic(); debugln!("[Success]"); // debug!(" Disabling PICs... "); // interrupts::disable_pic(); // debugln!("[Success]"); // debug!(" Initialising APIC... "); // enable_apic(); // debugln!("[Success]"); debug!(" Enabling Interrupts... "); x86_64::instructions::interrupts::enable(); debugln!("[Success]"); Ok(()) } #[panic_handler] fn panic(_info: &core::panic::PanicInfo<'_>) -> ! { debugln!("{:?}", _info); hcf() }