From c68a0ecaa443a4af1fd0e11c75f508d2129ed69a Mon Sep 17 00:00:00 2001 From: FantasyPvP <80643031+FantasyPvP@users.noreply.github.com> Date: Thu, 21 Nov 2024 10:28:12 +0000 Subject: [PATCH] fixed the interrupts issue --- kernel/src/main.rs | 4 +- kernel/src/sys/kernel/cpu/x86_64/apic.rs | 14 +++ kernel/src/sys/kernel/cpu/x86_64/gdt.rs | 35 +++++- .../src/sys/kernel/cpu/x86_64/interrupts.rs | 109 ++++++++++++++++-- kernel/src/sys/kernel/cpu/x86_64/mod.rs | 1 + .../kernel/drivers/framebuffer/textwriter.rs | 20 ++-- .../src/sys/kernel/drivers/serial/serial.rs | 55 +++++---- kernel/x86_64-kernel.json | 2 +- scripts/run.sh | 5 +- 9 files changed, 192 insertions(+), 53 deletions(-) create mode 100644 kernel/src/sys/kernel/cpu/x86_64/apic.rs diff --git a/kernel/src/main.rs b/kernel/src/main.rs index accc904..9dd12f4 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -20,7 +20,9 @@ pub extern "C" fn kmain() -> ! { GoofyAhhOS::init(); println!("Hello from GoofyAhhOS!"); - serial_println!("SERIAL OUT ACHIEVED :check:"); + // serial_println!("SERIAL OUT ACHIEVED :check:"); + + loop {} loop { let input: &str = serial_read(); diff --git a/kernel/src/sys/kernel/cpu/x86_64/apic.rs b/kernel/src/sys/kernel/cpu/x86_64/apic.rs new file mode 100644 index 0000000..73c461e --- /dev/null +++ b/kernel/src/sys/kernel/cpu/x86_64/apic.rs @@ -0,0 +1,14 @@ +// use core::arch::x86_64::__cpuid; + + + +// static IA32_APIC_BASE_MSR: u32 = 0x1b; +// static IA32_APIC_BASE_MSR_BSP: u32 = 0x100; +// static IA32_APIC_BASE_MSR_ENABLE: u32 = 0x800; + +// fn check_apic() -> bool { +// let edx = unsafe { +// __cpuid(1,) +// }.edx; +// return edx & CPU_ID_FEAT_EDX_APIC != 0 +// } \ No newline at end of file diff --git a/kernel/src/sys/kernel/cpu/x86_64/gdt.rs b/kernel/src/sys/kernel/cpu/x86_64/gdt.rs index 1f26a30..17fba1a 100644 --- a/kernel/src/sys/kernel/cpu/x86_64/gdt.rs +++ b/kernel/src/sys/kernel/cpu/x86_64/gdt.rs @@ -1,5 +1,5 @@ use x86_64::{ - instructions::tables::load_tss, registers::segmentation::{Segment, CS}, structures::{ + instructions::tables::load_tss, registers::segmentation::{Segment, CS, DS, ES, SS}, structures::{ gdt::{ Descriptor, GlobalDescriptorTable, SegmentSelector }, @@ -17,7 +17,7 @@ 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; + const STACK_SIZE: usize = 4096 * 8; static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); @@ -30,16 +30,36 @@ lazy_static! { lazy_static! { static ref GDT: (GlobalDescriptorTable, Selectors) = { + x86_64::instructions::interrupts::disable(); let mut gdt = GlobalDescriptorTable::new(); + // Kernel code segment let code_selector = gdt.append(Descriptor::kernel_code_segment()); + // Kernel data segment (needed for proper interrupt handling) + let data_selector = gdt.append(Descriptor::kernel_data_segment()); + // User segments (even if not used, helps with some hardware) + let user_data_selector = gdt.append(Descriptor::user_data_segment()); + let user_code_selector = gdt.append(Descriptor::user_code_segment()); + // TSS segment for interrupt stack switching let tss_selector = gdt.append(Descriptor::tss_segment(&TSS)); - (gdt, Selectors { code_selector, tss_selector }) + ( + gdt, + Selectors { + code_selector, + data_selector, + // user_code_selector, + // user_data_selector, + tss_selector, + } + ) }; } struct Selectors { code_selector: SegmentSelector, - tss_selector: SegmentSelector + data_selector: SegmentSelector, + // user_code_selector: SegmentSelector, + // user_data_selector: SegmentSelector, + tss_selector: SegmentSelector, } pub fn init() { @@ -47,8 +67,13 @@ pub fn init() { println_log!("Loaded GDT..."); unsafe { + // Load the segment selectors CS::set_reg(GDT.1.code_selector); load_tss(GDT.1.tss_selector); + + // // Set up data segments + // DS::set_reg(GDT.1.data_selector); + // ES::set_reg(GDT.1.data_selector); + SS::set_reg(GDT.1.data_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 46e4bc8..22eda97 100644 --- a/kernel/src/sys/kernel/cpu/x86_64/interrupts.rs +++ b/kernel/src/sys/kernel/cpu/x86_64/interrupts.rs @@ -2,7 +2,7 @@ use core::arch::asm; use lazy_static::lazy_static; use spin::lazy; -use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame}; +use x86_64::{instructions::{self, hlt, interrupts}, structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode}}; use crate::{println_log, serial_println, sys::kernel::cpu::gdt}; @@ -23,6 +23,7 @@ pub static PICS: spin::Mutex = spin::Mutex::new( #[repr(u8)] pub enum InterruptIndex { Timer = PIC_1_OFFSET, + Keyboard, } impl InterruptIndex { @@ -39,6 +40,9 @@ lazy_static! { static ref IDT: InterruptDescriptorTable = { let mut idt = InterruptDescriptorTable::new(); idt.breakpoint.set_handler_fn(breakpoint_handler); + idt.page_fault.set_handler_fn(page_fault_handler); + idt.general_protection_fault.set_handler_fn(general_protection_fault_handler); + unsafe { idt.double_fault.set_handler_fn(double_fault_handler) @@ -46,6 +50,10 @@ lazy_static! { } idt[InterruptIndex::Timer.as_u8()].set_handler_fn(timer_interrupt_handler); + + idt[InterruptIndex::Keyboard.as_u8()] + .set_handler_fn(keyboard_interrupt_handler); + idt }; } @@ -56,33 +64,112 @@ pub fn init() { unsafe { PICS.lock().initialize(); + PICS.lock().write_masks(0xfc, 0xff); + // println_log!("PIC initialized with masks: {:02x}, {:02x}", + // PICS.lock().read_masks()[0], + // PICS.lock().read_masks()[1] + // ); + println_log!("weird"); } - x86_64::instructions::interrupts::enable(); + unsafe { asm!("sti"); } println_log!("Enabled interrupts..."); } extern "x86-interrupt" fn timer_interrupt_handler(stack_frame: InterruptStackFrame) { - serial_println!("clock"); - println_log!("clock"); + without(|| { + println_log!("Timer interrupt!"); + }); unsafe { PICS.lock().notify_end_of_interrupt(InterruptIndex::Timer.as_u8()); } } +extern "x86-interrupt" fn general_protection_fault_handler( + stack_frame: InterruptStackFrame, + error_code: u64, +) { + without(|| { + // hlt(); + + let rsp: u64; + unsafe { + asm!("mov {}, rsp", out(reg) rsp); + } + serial_println!("EXCEPTION: GENERAL PROTECTION FAULT"); + serial_println!("Error Code: {:#x}", error_code); + serial_println!("RSP: {:#x}", rsp); + serial_println!("Instruction Pointer: {:#x}", stack_frame.instruction_pointer.as_u64()); + serial_println!("Stack Pointer: {:#x}", stack_frame.stack_pointer.as_u64()); + serial_println!("CPU Flags: {:#x}", stack_frame.cpu_flags.bits()); + serial_println!("Code Segment: {:?}", stack_frame.code_segment); + serial_println!("Stack Segment: {:?}", stack_frame.stack_segment); + }); + + panic!("EXCEPTION: GENERAL PROTECTION FAULT"); +} + extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) { - println_log!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame); - serial_println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame); + without(|| { + println_log!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame); + serial_println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame); + }); + + loop {} } extern "x86-interrupt" fn double_fault_handler(stack_frame: InterruptStackFrame, _error_code: u64) -> ! { - serial_println!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame); + without(|| { + serial_println!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame); + }); panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame) } -pub fn disable(func: impl Fn()) { - x86_64::instructions::interrupts::disable(); - func(); - x86_64::instructions::interrupts::enable(); +extern "x86-interrupt" fn page_fault_handler( + stack_frame: InterruptStackFrame, + error_code: PageFaultErrorCode, +) { + use x86_64::registers::control::Cr2; + + without(|| { + serial_println!("EXCEPTION: PAGE FAULT"); + serial_println!("Accessed Address: {:?}", Cr2::read()); + serial_println!("Error Code: {:?}", error_code); + serial_println!("Stack Frame: {:#?}", stack_frame); + }); + + panic!("EXCEPTION: PAGE FAULT"); +} + +pub fn without(func: impl Fn()) { + if are_enabled() { + unsafe { asm!("cli"); } + func(); + unsafe { asm!("sti"); } + } else { + func(); + } +} + +pub fn are_enabled() -> bool { + let flags: u64; + unsafe { + asm!("pushfq; pop {}", out(reg) flags); + } + flags & (1 << 9) != 0 // Bit 9 is the Interrupt Flag (IF) +} + +extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) { + use x86_64::instructions::port::Port; + + let mut port = Port::new(0x60); + + serial_println!("KEYBOARD INTERRUPT"); + + let scancode: u8 = unsafe { port.read() }; + + unsafe { + PICS.lock().notify_end_of_interrupt(InterruptIndex::Keyboard.as_u8()); + } } \ 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 c7cb8ef..b5e05b0 100644 --- a/kernel/src/sys/kernel/cpu/x86_64/mod.rs +++ b/kernel/src/sys/kernel/cpu/x86_64/mod.rs @@ -1,5 +1,6 @@ pub mod interrupts; pub mod gdt; +pub mod apic; mod pics; diff --git a/kernel/src/sys/kernel/drivers/framebuffer/textwriter.rs b/kernel/src/sys/kernel/drivers/framebuffer/textwriter.rs index a81aca7..25f8029 100644 --- a/kernel/src/sys/kernel/drivers/framebuffer/textwriter.rs +++ b/kernel/src/sys/kernel/drivers/framebuffer/textwriter.rs @@ -4,7 +4,7 @@ use core::fmt; use lazy_static::lazy_static; use spin::Mutex; -use crate::sys::kernel::cpu::interrupts; +use crate::sys::kernel::cpu::x86_64::interrupts; use super::{font::FONT, render::FRAMEBUFFER_WRITER}; @@ -125,7 +125,7 @@ impl core::fmt::Write for TextWriter { fn write(args: fmt::Arguments, fg_color: u32, bg_color: u32) { use core::fmt::Write; - interrupts::disable(|| { + interrupts::without(|| { let mut writer = TEXT_WRITER.lock(); writer.set_colour((fg_color, bg_color)); writer.write_fmt(args).unwrap(); @@ -146,13 +146,15 @@ pub fn _log(args: fmt::Arguments) { } pub fn clear_screen() { - let mut writer = TEXT_WRITER.lock(); - writer.text_line = 0; - writer.text_col = 0; - - if let Some(writer) = FRAMEBUFFER_WRITER.lock().as_mut() { - writer.clear(); - } + interrupts::without(|| { + let mut writer = TEXT_WRITER.lock(); + writer.text_line = 0; + writer.text_col = 0; + + if let Some(writer) = FRAMEBUFFER_WRITER.lock().as_mut() { + writer.clear(); + } + }); } #[macro_export] diff --git a/kernel/src/sys/kernel/drivers/serial/serial.rs b/kernel/src/sys/kernel/drivers/serial/serial.rs index a056d2f..85d97e5 100644 --- a/kernel/src/sys/kernel/drivers/serial/serial.rs +++ b/kernel/src/sys/kernel/drivers/serial/serial.rs @@ -1,19 +1,19 @@ -use core::fmt; +use core::{fmt, sync::atomic::{AtomicUsize, Ordering}}; use spin::Mutex; use lazy_static::lazy_static; use crate::sys::kernel::cpu::{inb, outb}; +use crate::sys::kernel::cpu::x86_64::interrupts; static PORT: u16 = 0x3f8; static mut BUFFER: [u8; 256] = [0; 256]; +static BUFFER_LEN: AtomicUsize = AtomicUsize::new(0); lazy_static!{ static ref SERIAL_WRITER: Mutex = Mutex::new(SerialWriter::new()); } -struct SerialWriter { - buffer_len: usize -} +struct SerialWriter; impl fmt::Write for SerialWriter { fn write_str(&mut self, s: &str) -> fmt::Result { @@ -45,9 +45,7 @@ impl SerialWriter { outb(PORT + 4, 0x0F); } - SerialWriter { - buffer_len: 0 - } + SerialWriter } // returnstrue if there is new data on the serial port @@ -68,15 +66,15 @@ impl SerialWriter { pub fn read_str_to_buffer(&mut self) { unsafe { while !self.serial_recieved() {}; - self.buffer_len = 0; + BUFFER_LEN.store(0, Ordering::SeqCst); - while self.serial_recieved() && self.buffer_len < 256 { + while self.serial_recieved() && BUFFER_LEN.load(Ordering::SeqCst) < 256 { let c = inb(PORT + 0); - BUFFER[self.buffer_len] = c; + BUFFER[BUFFER_LEN.load(Ordering::SeqCst)] = c; if c == b'\n' { break; } - self.buffer_len += 1; + BUFFER_LEN.fetch_add(1, Ordering::SeqCst); } }} @@ -89,19 +87,31 @@ impl SerialWriter { pub fn _serial_write(args: fmt::Arguments) { use core::fmt::Write; - SERIAL_WRITER.lock().write_fmt(args).unwrap(); + interrupts::without(|| { + SERIAL_WRITER.lock().write_fmt(args).unwrap(); + }) +} + +#[macro_use] +#[macro_export] +macro_rules! serial_println { + () => ($crate::serial_print!("\n")); + ($($arg:tt)*) => ($crate::serial_print!("{}\n", format_args!($($arg)*))); } pub fn serial_read() -> &'static str { - SERIAL_WRITER.lock().read_str_to_buffer(); - let i = SERIAL_WRITER.lock().buffer_len; - - if i == 0 { - return ""; - } + serial_println!("getting value!"); - unsafe { - return core::str::from_utf8(&BUFFER[..i - 1]).unwrap(); + interrupts::without(|| { + SERIAL_WRITER.lock().read_str_to_buffer(); + }); + + let i = BUFFER_LEN.load(Ordering::SeqCst); + + return unsafe { + if i != 0 { + core::str::from_utf8(&BUFFER[..i - 1]).unwrap() + } else { "" } } } @@ -110,8 +120,3 @@ macro_rules! serial_print { ($($arg:tt)*) => ($crate::_serial_write(format_args!($($arg)*))); } -#[macro_export] -macro_rules! serial_println { - () => ($crate::serial_print!("\n")); - ($($arg:tt)*) => ($crate::serial_print!("{}\n", format_args!($($arg)*))); -} \ No newline at end of file diff --git a/kernel/x86_64-kernel.json b/kernel/x86_64-kernel.json index 76085cc..f29aa32 100644 --- a/kernel/x86_64-kernel.json +++ b/kernel/x86_64-kernel.json @@ -16,7 +16,7 @@ "code-model": "kernel", "pre-link-args": { "ld.lld": [ - "--script=/home/fantasypvp/Projects/OSDev/GoofyAhhOS/kernel/linker.ld", + "--script=kernel/linker.ld", "-nostdlib", "--no-dynamic-linker", "-static", diff --git a/scripts/run.sh b/scripts/run.sh index da8c141..16a53c4 100755 --- a/scripts/run.sh +++ b/scripts/run.sh @@ -127,7 +127,7 @@ 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 -monitor telnet:127.0.0.1:1235,server" serial_flags="-serial stdio" fi @@ -158,6 +158,8 @@ check_test_res() { } +kvm_flag="" + trap 'check_test_res "tests completed"' ERR cd "$project_root" @@ -171,3 +173,4 @@ qemu-system-x86_64 -M q35 \ ${test_flags} \ ${debug_flags} \ ${QEMU_FLAGS:-} +