fixed the interrupts issue

This commit is contained in:
FantasyPvP
2024-11-21 10:28:12 +00:00
parent a4b0662983
commit c68a0ecaa4
9 changed files with 192 additions and 53 deletions
+3 -1
View File
@@ -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();
+14
View File
@@ -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
// }
+30 -5
View File
@@ -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);
}
}
+98 -11
View File
@@ -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<ChainedPics> = 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());
}
}
+1
View File
@@ -1,5 +1,6 @@
pub mod interrupts;
pub mod gdt;
pub mod apic;
mod pics;
@@ -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;
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();
}
if let Some(writer) = FRAMEBUFFER_WRITER.lock().as_mut() {
writer.clear();
}
});
}
#[macro_export]
+29 -24
View File
@@ -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<SerialWriter> = 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;
serial_println!("getting value!");
if i == 0 {
return "";
}
interrupts::without(|| {
SERIAL_WRITER.lock().read_str_to_buffer();
});
unsafe {
return core::str::from_utf8(&BUFFER[..i - 1]).unwrap();
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)*)));
}
+1 -1
View File
@@ -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",
+4 -1
View File
@@ -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:-}