diff --git a/config/limine.conf b/config/limine.conf index 0ffe391..3838f5a 100644 --- a/config/limine.conf +++ b/config/limine.conf @@ -1,5 +1,5 @@ # Timeout in seconds that Limine will use before automatically booting. -timeout: 5 +timeout: 1 # The entry name that will be displayed in the boot menu. /GoofyAhhOS @@ -7,4 +7,5 @@ timeout: 5 protocol: limine # Path to the kernel to boot. boot():/ represents the partition on which limine.conf is located. - kernel_path: boot():/boot/kernel \ No newline at end of file + kernel_path: boot():/boot/kernel + diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index f9dbd79..da246c2 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -9,6 +9,7 @@ spin = { version = "0.9.8", features = ["lazy"] } bitflags = { version = "2.4.0", default-features = false } lazy_static = { version = "1.5.0", features = ["spin_no_std"] } x86_64 = { version = "0.15.1" } +pic8259 = "0.11.0" [features] default = [] diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 3738c93..2518326 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -28,7 +28,7 @@ pub use sys::kernel::drivers::serial::{ }; pub fn init() { - sys::kernel::cpu::interrupts::init(); + sys::kernel::cpu::init(); } pub fn hcf() -> ! { diff --git a/kernel/src/sys/kernel/cpu/x86_64/gdt.rs b/kernel/src/sys/kernel/cpu/x86_64/gdt.rs new file mode 100644 index 0000000..1f26a30 --- /dev/null +++ b/kernel/src/sys/kernel/cpu/x86_64/gdt.rs @@ -0,0 +1,54 @@ +use x86_64::{ + instructions::tables::load_tss, registers::segmentation::{Segment, CS}, structures::{ + gdt::{ + Descriptor, GlobalDescriptorTable, SegmentSelector + }, + tss::TaskStateSegment, + }, VirtAddr +}; + +use lazy_static::lazy_static; + +use crate::println_log; + +pub const DOUBLE_FAULT_IST_INDEX: u16 = 0; + +lazy_static! { + static ref TSS: TaskStateSegment = { + let mut tss = TaskStateSegment::new(); + tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX as usize] = { + const STACK_SIZE: usize = 4096 * 5; + static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + + let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); + let stack_end = stack_start + STACK_SIZE.try_into().unwrap(); + stack_end + }; + tss + }; +} + +lazy_static! { + static ref GDT: (GlobalDescriptorTable, Selectors) = { + let mut gdt = GlobalDescriptorTable::new(); + let code_selector = gdt.append(Descriptor::kernel_code_segment()); + let tss_selector = gdt.append(Descriptor::tss_segment(&TSS)); + (gdt, Selectors { code_selector, tss_selector }) + }; +} + +struct Selectors { + code_selector: SegmentSelector, + tss_selector: SegmentSelector +} + +pub fn init() { + GDT.0.load(); + println_log!("Loaded GDT..."); + + unsafe { + CS::set_reg(GDT.1.code_selector); + load_tss(GDT.1.tss_selector); + } + +} \ No newline at end of file diff --git a/kernel/src/sys/kernel/cpu/x86_64/interrupts.rs b/kernel/src/sys/kernel/cpu/x86_64/interrupts.rs index 171e3b8..46e4bc8 100644 --- a/kernel/src/sys/kernel/cpu/x86_64/interrupts.rs +++ b/kernel/src/sys/kernel/cpu/x86_64/interrupts.rs @@ -4,15 +4,20 @@ use lazy_static::lazy_static; use spin::lazy; use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame}; -use crate::{println_log, serial_println}; +use crate::{println_log, serial_println, sys::kernel::cpu::gdt}; -use super::pics::ChainedPics; +// use super::pics::ChainedPics; + +use pic8259::ChainedPics; pub const PIC_1_OFFSET: u8 = 32; pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8; -pub static PICS: spin::Mutex = - spin::Mutex::new(unsafe { ChainedPics::new(PIC_1_OFFSET, PIC_2_OFFSET) }); +pub static PICS: spin::Mutex = spin::Mutex::new( + unsafe { + ChainedPics::new(PIC_1_OFFSET, PIC_2_OFFSET) + } +); #[derive(Debug, Clone, Copy)] #[repr(u8)] @@ -34,22 +39,35 @@ lazy_static! { static ref IDT: InterruptDescriptorTable = { let mut idt = InterruptDescriptorTable::new(); idt.breakpoint.set_handler_fn(breakpoint_handler); - idt.double_fault.set_handler_fn(double_fault_handler); - idt[InterruptIndex::Timer.as_u8()].set_handler_fn(clock_handler); + + unsafe { + idt.double_fault.set_handler_fn(double_fault_handler) + .set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX); + } + + idt[InterruptIndex::Timer.as_u8()].set_handler_fn(timer_interrupt_handler); idt }; } pub fn init() { IDT.load(); + println_log!("Loaded IDT..."); + + unsafe { + PICS.lock().initialize(); + } + + x86_64::instructions::interrupts::enable(); + println_log!("Enabled interrupts..."); } +extern "x86-interrupt" fn timer_interrupt_handler(stack_frame: InterruptStackFrame) { + serial_println!("clock"); + println_log!("clock"); -pub fn disable(func: impl Fn()) { unsafe { - asm!("cli", options(nomem, nostack, preserves_flags)); - func(); - asm!("sti", options(nomem, nostack, preserves_flags)); + PICS.lock().notify_end_of_interrupt(InterruptIndex::Timer.as_u8()); } } @@ -63,11 +81,8 @@ extern "x86-interrupt" fn double_fault_handler(stack_frame: InterruptStackFrame, panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame) } -extern "x86-interrupt" fn clock_handler(stack_frame: InterruptStackFrame) { - println_log!("EXCEPTION: CLOCK\n{:#?}", stack_frame); - serial_println!("EXCEPTION: CLOCK\n{:#?}", stack_frame); - - unsafe { - PICS.lock().notify_end_of_interrupt(InterruptIndex::Timer.as_u8()); - } +pub fn disable(func: impl Fn()) { + x86_64::instructions::interrupts::disable(); + func(); + x86_64::instructions::interrupts::enable(); } \ No newline at end of file diff --git a/kernel/src/sys/kernel/cpu/x86_64/mod.rs b/kernel/src/sys/kernel/cpu/x86_64/mod.rs index c97cf49..c7cb8ef 100644 --- a/kernel/src/sys/kernel/cpu/x86_64/mod.rs +++ b/kernel/src/sys/kernel/cpu/x86_64/mod.rs @@ -1,4 +1,9 @@ pub mod interrupts; +pub mod gdt; + mod pics; -pub use interrupts::*; +pub fn init() { + gdt::init(); + interrupts::init(); +} \ No newline at end of file diff --git a/scripts/run.sh b/scripts/run.sh index 007fd1c..da8c141 100755 --- a/scripts/run.sh +++ b/scripts/run.sh @@ -127,7 +127,8 @@ if [ $is_test -eq 1 ]; then serial_flags="-serial stdio" else test_flags="" - serial_flags="-serial tcp:127.0.0.1:1234,server,nowait" + # serial_flags="-serial tcp:127.0.0.1:1234,server,nowait" + serial_flags="-serial stdio" fi # Run in QEMU @@ -139,7 +140,25 @@ else info "Running OS in QEMU..." fi -echo "test: " $is_test +check_test_res() { + qemu_exit_code=$? + if [ $qemu_exit_code -eq 33 ]; then + # Success case (0x10 << 1) | 1 = 33 + info "All tests passed" + exit 0 + elif [ $qemu_exit_code -eq 35 ]; then + # Failure case (0x11 << 1) | 1 = 35 + warning "Some tests failed" + exit 1 + else + # Any other exit code is treated as a failure + warning "Some tests failed" + exit 1 + fi +} + + +trap 'check_test_res "tests completed"' ERR cd "$project_root" qemu-system-x86_64 -M q35 \ @@ -152,23 +171,3 @@ qemu-system-x86_64 -M q35 \ ${test_flags} \ ${debug_flags} \ ${QEMU_FLAGS:-} - -# Get QEMU's exit code -qemu_exit_code=$? - -# If this is a test run, translate QEMU exit codes to test exit codes -if [ $is_test -eq 1 ]; then - if [ $qemu_exit_code -eq 33 ]; then - # Success case (0x10 << 1) | 1 = 33 - exit 0 - elif [ $qemu_exit_code -eq 35 ]; then - # Failure case (0x11 << 1) | 1 = 35 - exit 1 - else - # Any other exit code is treated as a failure - exit 1 - fi -else - # For non-test runs, pass through the exit code - exit $qemu_exit_code -fi