diff --git a/Cargo.lock b/Cargo.lock index 3a8d5b2..819793c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -586,6 +586,7 @@ dependencies = [ "limine", "linked_list_allocator", "log", + "pic8259", "slab", "spin 0.9.4", "uart_16550", diff --git a/ableos/src/arch/x86_64/gdt.rs b/ableos/src/arch/x86_64/gdt.rs index 5758117..b693293 100644 --- a/ableos/src/arch/x86_64/gdt.rs +++ b/ableos/src/arch/x86_64/gdt.rs @@ -39,6 +39,7 @@ pub fn init() { use x86_64::instructions::segmentation::{Segment, CS}; use x86_64::instructions::tables::load_tss; + log::debug!("Initialising GDT"); GDT.0.load(); unsafe { CS::set_reg(GDT.1.code_selector); diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 2a111c8..830ba15 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -17,5 +17,6 @@ features = ["alloc"] [target.'cfg(target_arch = "x86_64")'.dependencies] limine = "0.1" +pic8259 = "0.10" uart_16550 = "0.2" x86_64 = "0.14" diff --git a/kernel/src/arch/x86_64/allocator.rs b/kernel/src/arch/x86_64/allocator.rs index d92cb45..8cf17c1 100644 --- a/kernel/src/arch/x86_64/allocator.rs +++ b/kernel/src/arch/x86_64/allocator.rs @@ -12,6 +12,7 @@ use crate::allocator::{HEAP_SIZE, HEAP_START}; static ALLOCATOR: LockedHeap = LockedHeap::empty(); pub unsafe fn init_alloc() -> Result<(), MapToError> { + log::info!("Initialising kernel heap allocator"); let page_range = Page::range_inclusive( Page::containing_address(VirtAddr::new(HEAP_START as u64)), Page::containing_address(VirtAddr::new(HEAP_START as u64) + HEAP_SIZE - 1u64), diff --git a/kernel/src/arch/x86_64/gdt.rs b/kernel/src/arch/x86_64/gdt.rs new file mode 100644 index 0000000..63ef734 --- /dev/null +++ b/kernel/src/arch/x86_64/gdt.rs @@ -0,0 +1,57 @@ +use spin::Lazy; +use x86_64::{ + structures::{ + gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector}, + tss::TaskStateSegment, + }, + VirtAddr, +}; + +pub const DOUBLE_FAULT_IX: u16 = 0; + +pub unsafe fn init() { + use x86_64::instructions::segmentation::{Segment, CS, DS}; + use x86_64::instructions::tables::load_tss; + + log::info!("Initialising GDT"); + GDT.0.load(); + unsafe { + CS::set_reg(GDT.1.kcode); + DS::set_reg(GDT.1.kdata); + load_tss(GDT.1.tss); + } +} + +struct Selectors { + kcode: SegmentSelector, + kdata: SegmentSelector, + tss: SegmentSelector, + udata: SegmentSelector, + ucode: SegmentSelector, +} + +static TSS: Lazy = Lazy::new(|| { + let mut tss = TaskStateSegment::new(); + tss.interrupt_stack_table[usize::from(DOUBLE_FAULT_IX)] = { + const SIZE: usize = 5 * 1024; + let stack = unsafe { + alloc::alloc::alloc_zeroed( + alloc::alloc::Layout::from_size_align(SIZE, 1).expect("stack pointer"), + ) + }; + VirtAddr::from_ptr(stack) + SIZE + }; + tss +}); + +static GDT: Lazy<(GlobalDescriptorTable, Selectors)> = Lazy::new(|| { + let mut gdt = GlobalDescriptorTable::new(); + let sels = Selectors { + kcode: gdt.add_entry(Descriptor::kernel_code_segment()), + kdata: gdt.add_entry(Descriptor::kernel_data_segment()), + tss: gdt.add_entry(Descriptor::tss_segment(&TSS)), + udata: gdt.add_entry(Descriptor::user_data_segment()), + ucode: gdt.add_entry(Descriptor::user_code_segment()), + }; + (gdt, sels) +}); diff --git a/kernel/src/arch/x86_64/idt.rs b/kernel/src/arch/x86_64/idt.rs new file mode 100644 index 0000000..6eeb358 --- /dev/null +++ b/kernel/src/arch/x86_64/idt.rs @@ -0,0 +1,52 @@ +use pic8259::ChainedPics; +use spin::{Lazy, Mutex}; +use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode}; + +pub const PIC_1_OFFSET: u8 = 32; +pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8; + +static PICS: Mutex = + Mutex::new(unsafe { ChainedPics::new(PIC_1_OFFSET, PIC_2_OFFSET) }); + +pub unsafe fn init() { + log::info!("Initialising IDT"); + IDT.load(); + PICS.lock().initialize(); + x86_64::instructions::interrupts::enable(); +} + +#[repr(u8)] +enum Interrupt { + Timer = PIC_1_OFFSET, +} + +static IDT: Lazy = Lazy::new(|| { + let mut idt = InterruptDescriptorTable::new(); + unsafe { + idt.double_fault + .set_handler_fn(double_fault) + .set_stack_index(super::gdt::DOUBLE_FAULT_IX); + } + idt.page_fault.set_handler_fn(page_fault); + idt[Interrupt::Timer as usize].set_handler_fn(timer); + idt +}); + +extern "x86-interrupt" fn double_fault(stack_frame: InterruptStackFrame, error_code: u64) -> ! { + panic!("Double fault: error code {error_code} \n{stack_frame:#?}") +} + +extern "x86-interrupt" fn page_fault( + stack_frame: InterruptStackFrame, + error_code: PageFaultErrorCode, +) { + panic!("Page fault ({error_code:?}): {stack_frame:?}") +} + +extern "x86-interrupt" fn timer(_: InterruptStackFrame) { + unsafe { eoi(Interrupt::Timer as u8) }; +} + +unsafe fn eoi(i: u8) { + PICS.lock().notify_end_of_interrupt(i); +} diff --git a/kernel/src/arch/x86_64/memory.rs b/kernel/src/arch/x86_64/memory.rs index 866bbde..f33e761 100644 --- a/kernel/src/arch/x86_64/memory.rs +++ b/kernel/src/arch/x86_64/memory.rs @@ -10,6 +10,7 @@ pub static FRAME_ALLOC: Once> = Once::new(); /// Initialise page table pub unsafe fn init_pt(phys_base: VirtAddr) { + log::info!("Retrieving page table"); PAGE_TABLE.call_once(|| { Mutex::new(OffsetPageTable::new( &mut *((phys_base @@ -25,6 +26,7 @@ pub unsafe fn init_pt(phys_base: VirtAddr) { /// Initialise page frame allocator pub unsafe fn init_falloc(mmap: &'static [LimineMemmapEntry]) { + log::info!("Initialising frame allocator"); FRAME_ALLOC.call_once(|| Mutex::new(FrameAlloc::new(mmap))); } diff --git a/kernel/src/arch/x86_64/mod.rs b/kernel/src/arch/x86_64/mod.rs index 60b567f..921aa25 100644 --- a/kernel/src/arch/x86_64/mod.rs +++ b/kernel/src/arch/x86_64/mod.rs @@ -4,6 +4,8 @@ use uart_16550::SerialPort; use x86_64::VirtAddr; mod allocator; +mod gdt; +mod idt; mod memory; static SERIAL_CONSOLE: Mutex = Mutex::new(unsafe { SerialPort::new(0x3f8) }); @@ -34,6 +36,8 @@ unsafe extern "C" fn _kernel_start() -> ! { ); allocator::init_alloc().expect("tried to initialise allocator"); + gdt::init(); + idt::init(); crate::kmain::kmain() } @@ -41,5 +45,12 @@ unsafe extern "C" fn _kernel_start() -> ! { /// Format args to serial console pub fn serial_fmt(args: core::fmt::Arguments<'_>) -> core::fmt::Result { use core::fmt::Write; - SERIAL_CONSOLE.lock().write_fmt(args) + x86_64::instructions::interrupts::without_interrupts(|| SERIAL_CONSOLE.lock().write_fmt(args)) +} + +/// Spin loop +pub fn sloop() -> ! { + loop { + x86_64::instructions::hlt(); + } } diff --git a/kernel/src/kmain.rs b/kernel/src/kmain.rs index 577589a..b898fb8 100644 --- a/kernel/src/kmain.rs +++ b/kernel/src/kmain.rs @@ -1,5 +1,6 @@ //! AbleOS Kernel Entrypoint pub fn kmain() -> ! { - loop {} + log::trace!("Entered kmain"); + crate::arch::sloop() } diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 6b17431..e83f633 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -1,14 +1,19 @@ //! The ableOS kernel. -#![feature(alloc_error_handler, prelude_import)] +#![feature( + abi_x86_interrupt, + alloc_error_handler, + panic_info_message, + prelude_import +)] #![no_std] extern crate alloc; pub mod allocator; pub mod arch; -pub mod logger; pub mod kmain; +pub mod logger; pub mod task; use versioning::Version; @@ -22,5 +27,23 @@ pub const VERSION: Version = Version { #[panic_handler] fn panic(info: &core::panic::PanicInfo) -> ! { + // TODO: Better panic handler + let _ = crate::arch::serial_fmt(format_args!( + "\x1b[1m\x1b[4m\x1b[38;5;125mKernel Panic\x1b[0m\r\n", + )); + + if let Some(loc) = info.location() { + let _ = crate::arch::serial_fmt(format_args!( + "Location: {} : {} / {}\r\n", + loc.file(), + loc.line(), + loc.column() + )); + } + + if let Some(msg) = info.message() { + let _ = crate::arch::serial_fmt(format_args!("{msg}\r\n")); + } + loop {} }