diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 235e137..27aecf6 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -20,6 +20,7 @@ harness = false [[test]] name = "stack_overflow" harness = false +test = false # currently doesn't work reliably because the stack corrupts something [dependencies] bit_field = "0.10.3" diff --git a/kernel/src/boot.rs b/kernel/src/boot.rs index 74f9799..b1ad0fd 100644 --- a/kernel/src/boot.rs +++ b/kernel/src/boot.rs @@ -100,12 +100,19 @@ const impl Default for MemoryRegion { pub struct BootInfo { pub hhdm_base: u64, pub memory_map: &'static [MemoryRegion], + pub executable_file: Option<&'static [u8]>, } pub static BOOT_INFO: OnceLock = OnceLock::new(); static mut MEMORY_MAP: [MemoryRegion; 128] = [MemoryRegion::default(); 128]; -pub fn init_boot_info>(hhdm_base: u64, memory_map: I) { +pub fn init_boot_info>( + hhdm_base: u64, + memory_map: I, + executable_file: Option<&'static [u8]>, +) { + _ = crate::memory::HHDM_BASE.try_insert(hhdm_base); + BOOT_INFO.initialize(|| { for (i, region) in memory_map.enumerate() { assert!(i < 128, "Memory map has more than 128 entries"); @@ -117,6 +124,7 @@ pub fn init_boot_info>(hhdm_base: u64, memory_m Ok::<_, !>(BootInfo { hhdm_base, memory_map: unsafe { (&raw const MEMORY_MAP).as_ref_unchecked() }, + executable_file, }) }); } diff --git a/kernel/src/limine.rs b/kernel/src/limine.rs index 64407ed..2a349b9 100644 --- a/kernel/src/limine.rs +++ b/kernel/src/limine.rs @@ -1,4 +1,6 @@ -use core::{cell::UnsafeCell, ffi::CStr, fmt::Debug, ptr::NonNull}; +use core::{cell::UnsafeCell, fmt::Debug, ptr::NonNull}; + +use crate::serial_println; #[repr(C)] pub struct BaseRevision(UnsafeCell<[u64; 3]>); @@ -326,6 +328,46 @@ impl LimineFile { } } +#[used] +#[unsafe(link_section = ".limine_requests_start")] +static LIMINE_REQUESTS_START: RequestsStartMarker = REQUESTS_START_MARKER; + #[used] #[unsafe(link_section = ".limine_requests")] pub static EXECUTABLE_FILE_REQUEST: ExecutableFileRequest = ExecutableFileRequest::new(); + +#[used] +#[unsafe(link_section = ".limine_requests")] +pub static LIMINE_BASE_REVISION: BaseRevision = BaseRevision::from_revision(6); + +#[used] +#[unsafe(link_section = ".limine_requests")] +pub static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new(); + +#[used] +#[unsafe(link_section = ".limine_requests")] +pub static HHDM_REQUEST: HhdmRequest = HhdmRequest::new(); + +#[used] +#[unsafe(link_section = ".limine_requests")] +pub static MEMMAP_REQUEST: MemMapRequest = MemMapRequest::new(); + +#[used] +#[unsafe(link_section = ".limine_requests_end")] +static LIMINE_REQUESTS_END: RequestsEndMarker = REQUESTS_END_MARKER; + +pub fn init_limine_boot_info() { + crate::boot::init_boot_info( + HHDM_REQUEST + .offset() + .expect("HHDM offset not provided by bootloader"), + MEMMAP_REQUEST + .entries() + .iter() + .inspect(|e| { + serial_println!("{e:?}"); + }) + .map(|&&e| e.into()), + EXECUTABLE_FILE_REQUEST.file().map(|f| f.bytes()), + ); +} diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 7f9c3f8..485b672 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -23,25 +23,9 @@ static GDT: LazyLock = LazyLock::new(GlobalDescriptorTabl #[unsafe(no_mangle)] extern "C" fn _start() -> ! { kernel::logger::init(log::LevelFilter::Trace); - assert!(limine_requests::LIMINE_BASE_REVISION.is_supported()); + assert!(kernel::limine::LIMINE_BASE_REVISION.is_supported()); - _ = kernel::memory::HHDM_BASE - .try_insert( - limine_requests::HHDM_REQUEST - .offset() - .expect("HHDM offset not provided by bootloader"), - ) - .expect("HHDM offset already set"); - - kernel::boot::init_boot_info( - limine_requests::HHDM_REQUEST - .offset() - .expect("HHDM offset not provided by bootloader"), - limine_requests::MEMMAP_REQUEST - .entries() - .iter() - .map(|&&e| e.into()), - ); + kernel::limine::init_limine_boot_info(); kernel::serial_println!( "HHDM offset: 0x{:#x}", @@ -50,13 +34,12 @@ extern "C" fn _start() -> ! { kernel::serial_println!( "Memory map: {:#?}", - limine_requests::MEMMAP_REQUEST.entries() + kernel::limine::MEMMAP_REQUEST.entries() ); GDT.load(); IDT.load(); - kernel::serial_println!("entry point: 0x{:x}", _start as *const () as usize); kernel::serial_println!( "entry point phy: {:?}", @@ -75,7 +58,7 @@ extern "C" fn _start() -> ! { kernel::serial_println!("PMM: {pmm:#?}"); - let fb = limine_requests::FRAMEBUFFER_REQUEST + let fb = kernel::limine::FRAMEBUFFER_REQUEST .framebuffers() .first() .expect("No framebuffer found"); @@ -95,34 +78,3 @@ extern "C" fn _start() -> ! { kernel::x86_64::halt_loop() } - -mod limine_requests { - use kernel::limine::{ - BaseRevision, FramebufferRequest, REQUESTS_END_MARKER, REQUESTS_START_MARKER, - RequestsEndMarker, RequestsStartMarker, - }; - - #[used] - #[unsafe(link_section = ".limine_requests_start")] - static LIMINE_REQUESTS_START: RequestsStartMarker = REQUESTS_START_MARKER; - - #[used] - #[unsafe(link_section = ".limine_requests")] - pub static LIMINE_BASE_REVISION: BaseRevision = BaseRevision::from_revision(6); - - #[used] - #[unsafe(link_section = ".limine_requests")] - pub static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new(); - - #[used] - #[unsafe(link_section = ".limine_requests")] - pub static HHDM_REQUEST: kernel::limine::HhdmRequest = kernel::limine::HhdmRequest::new(); - - #[used] - #[unsafe(link_section = ".limine_requests")] - pub static MEMMAP_REQUEST: kernel::limine::MemMapRequest = kernel::limine::MemMapRequest::new(); - - #[used] - #[unsafe(link_section = ".limine_requests_end")] - static LIMINE_REQUESTS_END: RequestsEndMarker = REQUESTS_END_MARKER; -} diff --git a/kernel/src/x86_64/backtrace.rs b/kernel/src/x86_64/backtrace.rs index 4b551d0..01ea8fe 100644 --- a/kernel/src/x86_64/backtrace.rs +++ b/kernel/src/x86_64/backtrace.rs @@ -1,4 +1,4 @@ -use core::ffi::{CStr, c_void}; +use core::ffi::c_void; use crate::{ limine::LimineFile, diff --git a/kernel/src/x86_64/gdt.rs b/kernel/src/x86_64/gdt.rs index bbb8cf2..ee15688 100644 --- a/kernel/src/x86_64/gdt.rs +++ b/kernel/src/x86_64/gdt.rs @@ -472,7 +472,6 @@ const PRIVILEGE_STACK_TABLE_SIZE: usize = 3; const INTERRUPT_STACK_TABLE_SIZE: usize = 7; #[repr(C, packed(4))] -#[derive(Debug)] pub struct TaskStateSegment { _reserved1: [u8; 4], pub privilege_stack_table: [u64; PRIVILEGE_STACK_TABLE_SIZE], @@ -482,6 +481,31 @@ pub struct TaskStateSegment { pub iomap_base: u16, } +impl Debug for TaskStateSegment { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut dbg = f.debug_struct("TaskStateSegment"); + + let rsps = self.privilege_stack_table; + let ists = self.interrupt_stack_table; + + dbg.field("RSP0", &format_args!("{:#x}", rsps[0])) + .field("RSP1", &format_args!("{:#x}", rsps[1])) + .field("RSP2", &format_args!("{:#x}", rsps[2])); + + dbg.field("IST1", &format_args!("{:#x}", ists[0])) + .field("IST2", &format_args!("{:#x}", ists[1])) + .field("IST3", &format_args!("{:#x}", ists[2])) + .field("IST4", &format_args!("{:#x}", ists[3])) + .field("IST5", &format_args!("{:#x}", ists[4])) + .field("IST6", &format_args!("{:#x}", ists[5])) + .field("IST7", &format_args!("{:#x}", ists[6])); + + dbg.field("iomap_base", &format_args!("{:#x}", self.iomap_base)); + + dbg.finish() + } +} + impl TaskStateSegment { pub const fn new() -> Self { Self { @@ -514,7 +538,7 @@ pub const MC_STACK: u8 = 2; pub const PF_STACK: u8 = 3; const STACK_SIZE: usize = super::PAGE_SIZE * 5; -#[repr(align(16))] +#[repr(align(4096))] pub struct Stack(MaybeUninit<[u8; STACK_SIZE]>); impl Stack { diff --git a/kernel/src/x86_64/idt.rs b/kernel/src/x86_64/idt.rs index 51c3fdd..0b15383 100644 --- a/kernel/src/x86_64/idt.rs +++ b/kernel/src/x86_64/idt.rs @@ -523,7 +523,12 @@ extern "C" fn global_interrupt_handler( serial_println!("Breakpoint interrupt handled successfully."); } ExceptionVector::PAGE_FAULT => { - serial_println!("Page fault occurred! Error code: {:#x}", error_code); + let cr2 = super::registers::Cr2::read(); + serial_println!( + "Page fault occurred! Error code: {:#x} CR2: {:#x}", + error_code, + cr2.0 + ); debug_backtrace(&Context { rip: frame.instruction_pointer, registers: *registers, diff --git a/kernel/src/x86_64/registers.rs b/kernel/src/x86_64/registers.rs index 7cfce74..3e98cac 100644 --- a/kernel/src/x86_64/registers.rs +++ b/kernel/src/x86_64/registers.rs @@ -64,6 +64,17 @@ bitflags::bitflags! { } } +pub struct Cr2(pub u64); +impl Cr2 { + pub fn read() -> Self { + let value: u64; + unsafe { + asm!("mov {}, cr2", out(reg) value, options(nomem, nostack, preserves_flags)); + } + Self(value) + } +} + impl Cr4 { pub fn read() -> Self { let value: u64; diff --git a/kernel/tests/stack_overflow.rs b/kernel/tests/stack_overflow.rs index cedb005..b79432b 100644 --- a/kernel/tests/stack_overflow.rs +++ b/kernel/tests/stack_overflow.rs @@ -5,6 +5,7 @@ use core::{cell::UnsafeCell, mem::offset_of}; use kernel::{ + serial_println, sync::LazyLock, x86_64::{ gdt::{DF_STACK, GlobalDescriptorTable, RING0}, @@ -17,6 +18,7 @@ pub static GDT: LazyLock = LazyLock::new(GlobalDescriptor #[unsafe(export_name = "_start")] pub extern "C" fn main() -> ! { kernel::serial_println!("Hello, world!"); + kernel::limine::init_limine_boot_info(); GDT.load(); kernel::serial_println!("[ok] GDT loaded");