diff --git a/kernel/src/serial.rs b/kernel/src/serial.rs index 7cf47c0..62564db 100644 --- a/kernel/src/serial.rs +++ b/kernel/src/serial.rs @@ -300,11 +300,11 @@ pub mod uart_16550 { #[derive(Debug, Clone, Copy, Default)] pub enum BaudRate { + #[default] Baud115200, Baud57600, Baud38400, Baud19200, - #[default] Baud9600, } diff --git a/kernel/src/x86_64.rs b/kernel/src/x86_64.rs index be526e4..57645c4 100644 --- a/kernel/src/x86_64.rs +++ b/kernel/src/x86_64.rs @@ -67,3 +67,29 @@ pub struct Registers { pub rcx: u64, pub rax: u64, } + +bitflags::bitflags! { + #[repr(transparent)] + #[derive(Debug, Clone, Copy, PartialEq, Eq)] + pub struct RFlags: u64 { + const CARRY = 1 << 0; + const DEFAULT = 1 << 1; + const PARITY = 1 << 2; + const AUXILIARY_CARRY = 1 << 4; + const ZERO = 1 << 6; + const SIGN = 1 << 7; + const TRAP = 1 << 8; + const INTERRUPT_ENABLE = 1 << 9; + const DIRECTION = 1 << 10; + const OVERFLOW = 1 << 11; + const IOPL_LOW = 1 << 12; + const IOPL_HIGH = 1 << 13; + const NESTED_TASK = 1 << 14; + const RESUME = 1 << 16; + const VIRTUAL_8086_MODE = 1 << 17; + const ALIGNMENT_CHECK = 1 << 18; + const VIRTUAL_INTERRUPT_FLAG = 1 << 19; + const VIRTUAL_INTERRUPT_PENDING = 1 << 20; + const ID_FLAG = 1 << 21; + } +} diff --git a/kernel/src/x86_64/idt.rs b/kernel/src/x86_64/idt.rs index 5731675..da7c4a7 100644 --- a/kernel/src/x86_64/idt.rs +++ b/kernel/src/x86_64/idt.rs @@ -2,7 +2,10 @@ use core::{arch::naked_asm, fmt::Debug, marker::PhantomData, ops::Deref, ptr::No use bit_field::BitField; -use crate::{serial_println, x86_64::Registers}; +use crate::{ + serial_println, + x86_64::{RFlags, Registers}, +}; #[derive(Clone, Copy)] #[repr(C)] @@ -201,21 +204,36 @@ impl EntryOptions { } } -#[derive(Debug, Clone, Copy)] +#[derive(Clone, Copy)] #[repr(C)] pub struct InterruptStackFrameInner { pub instruction_pointer: u64, pub code_segment: u16, _reserved: [u16; 3], + pub flags: RFlags, pub stack_pointer: u64, pub stack_segment: u16, _reserved2: [u16; 3], } -#[derive(Debug)] #[repr(transparent)] pub struct InterruptStackFrame(InterruptStackFrameInner); +impl Debug for InterruptStackFrame { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("InterruptStackFrame") + .field( + "instruction_pointer", + &format_args!("{:#x}", self.instruction_pointer), + ) + .field("code_segment", &format_args!("{:#x}", self.code_segment)) + .field("flags", &self.flags) + .field("stack_pointer", &format_args!("{:#x}", self.stack_pointer)) + .field("stack_segment", &format_args!("{:#x}", self.stack_segment)) + .finish() + } +} + impl Deref for InterruptStackFrame { type Target = InterruptStackFrameInner; @@ -344,19 +362,6 @@ impl InterruptDescriptorTable { } } - pub fn set_interrupt)>( - &mut self, - _handler: T, - ) { - let wrapper = InterruptHandlerWrapper::(PhantomData); - let handler_addr = handler_entry_by_index::(wrapper); - - unsafe { - let entry = self.as_mut_type_erased().get_unchecked_mut(N as usize); - entry.set_handler(handler_addr); - } - } - pub unsafe fn as_type_erased(&self) -> &[Entry; 256] { unsafe { core::mem::transmute::<&Self, &[Entry; 256]>(self) } } @@ -424,6 +429,7 @@ extern "C" fn interrupt_dispatcher() { "pop rdx", "pop rcx", "pop rax", + "add rsp, 16", // pop the interrupt index and error code "iretq", registers_size = const { core::mem::size_of::() }, global_handler = sym global_interrupt_handler, @@ -437,7 +443,7 @@ extern "C" fn global_interrupt_handler( registers: &Registers, ) { crate::serial_println!( - "Interrupt {} occurred! Error code: {:#x}, Frame: {:?}, Registers: {:?}", + "Interrupt {} occurred! Error code: {:#x}, Frame: {:#?}, Registers: {:#?}", index, error_code, frame, @@ -445,204 +451,15 @@ extern "C" fn global_interrupt_handler( ); } -pub type InterruptHandler = extern "x86-interrupt" fn(InterruptStackFrame); -pub type InterruptWithErrorCodeHandler = extern "x86-interrupt" fn(InterruptStackFrame, u64); -pub type PageFaultHandler = extern "x86-interrupt" fn(InterruptStackFrame, PageFaultErrorCode); -pub type DoubleFaultHandler = extern "x86-interrupt" fn(InterruptStackFrame, u64) -> !; -pub type DivergingHandler = extern "x86-interrupt" fn(InterruptStackFrame) -> !; -pub type GeneralHandler = fn(InterruptStackFrame, index: u8, error_code: Option); - -macro_rules! impl_handler_type { - ($($handler_type:ty),*) => { - $( - impl ToAddress for $handler_type { - fn to_address(&self) -> u64 { - *self as *const () as u64 - } - } - )* - }; -} - -impl_handler_type!( - InterruptHandler, - InterruptWithErrorCodeHandler, - PageFaultHandler, - DoubleFaultHandler, - DivergingHandler -); - -pub trait HandleGeneratorTrait { - fn get_handler_addr(&self) -> u64; -} - -fn handler_entry_by_index(handler: InterruptHandlerWrapper) -> u64 -where - T: Fn(InterruptStackFrame, u8, Option) + Sized, -{ - if IDX == 8 { - // Double fault - DoubleFaultHandlerTrait::::get_handler_addr(&handler) - } else if IDX == 10 { - // Invalid TSS - InterruptWithErrorCodeHandlerTrait::::get_handler_addr(&handler) - } else if IDX == 11 { - // Segment not present - InterruptWithErrorCodeHandlerTrait::::get_handler_addr(&handler) - } else if IDX == 12 { - // Stack segment fault - InterruptWithErrorCodeHandlerTrait::::get_handler_addr(&handler) - } else if IDX == 13 { - // General protection fault - InterruptWithErrorCodeHandlerTrait::::get_handler_addr(&handler) - } else if IDX == 14 { - // Page fault - PageFaultHandlerTrait::::get_handler_addr(&handler) - } else if IDX == 17 { - // Alignment check - InterruptWithErrorCodeHandlerTrait::::get_handler_addr(&handler) - } else if IDX == 18 { - // Machine check - DivergingHandlerTrait::::get_handler_addr(&handler) - } else if IDX == 29 { - // VMM communication exception - InterruptWithErrorCodeHandlerTrait::::get_handler_addr(&handler) - } else if IDX == 30 { - // Security exception - InterruptWithErrorCodeHandlerTrait::::get_handler_addr(&handler) - } else { - // All other interrupts - InterruptHandlerTrait::::get_handler_addr(&handler) - } -} - -pub struct InterruptHandlerWrapper(PhantomData T>); - -pub trait InterruptErrorCode: Sized { - fn as_u64(&self) -> u64; -} - -impl InterruptErrorCode for u64 { - fn as_u64(&self) -> u64 { - *self - } -} - -impl InterruptErrorCode for PageFaultErrorCode { - fn as_u64(&self) -> u64 { - self.bits() - } -} - -macro_rules! interrupt_error_param { - ( $err:ty) => { - $err - }; - () => { - () - }; - ($val:ident: $err:ty) => { - Some(InterruptErrorCode::as_u64(&$val)) - }; - (err:) => { - None - }; -} - -macro_rules! interrupt_return_expr { - ( $expr:ty) => { - $crate::serial_println!("halt looping after unrecoverable interrupt"); - $crate::x86_64::halt_loop() - }; - () => { - () - }; -} - -macro_rules! impl_interrupt_handler_trait { - (trait $trait_name:ident (InterruptStackFrame $(, $err:ty)?) $(-> $ret:ty)?) => { - pub trait $trait_name - where - T: Fn(InterruptStackFrame, u8, Option), - { - extern "x86-interrupt" fn handler( - frame: InterruptStackFrame, - $( err: interrupt_error_param!{$err})*) - $(-> $ret)* { - assert_eq!( - core::mem::size_of::(), - 0, - "Handler type must be zero-sized" - ); - let f: T = unsafe { core::mem::transmute_copy::<(), T>(&()) }; - $crate::serial_println!("calling interrupt handler {} with {:?}", IDX, core::any::type_name::()); - f(frame, IDX, interrupt_error_param!{err: $($err)*}); - $crate::serial_println!("returning from interrupt handler {} with {:?}", IDX, core::any::type_name::()); - interrupt_return_expr!{$($ret)*} - } - - fn get_handler_addr(&self) -> u64 { - Self::handler as *const () as u64 - } - } - - impl $trait_name for InterruptHandlerWrapper - where - T: Fn(InterruptStackFrame, u8, Option), - { - } - }; -} - -impl_interrupt_handler_trait!(trait InterruptHandlerTrait(InterruptStackFrame)); -impl_interrupt_handler_trait!(trait DivergingHandlerTrait(InterruptStackFrame) -> !); -impl_interrupt_handler_trait!(trait InterruptWithErrorCodeHandlerTrait(InterruptStackFrame, u64)); -impl_interrupt_handler_trait!(trait PageFaultHandlerTrait(InterruptStackFrame, PageFaultErrorCode)); -impl_interrupt_handler_trait!(trait DoubleFaultHandlerTrait(InterruptStackFrame, u64) -> !); - -fn my_handler(frame: InterruptStackFrame, index: u8) { - // Handle the interrupt here - crate::serial_println!("Interrupt {} occurred!", index); -} - -// fn asdf() { -// let wrapper = InterruptHandlerWrapper::<>(PhantomData); -// let handler = InterruptHandlerTrait::<32, _>::get_handler(&wrapper); -// } - #[cfg_attr(test, test_case)] fn test_interrupt_handler_trait() { - let mut idt = InterruptDescriptorTable::new_empty(); - idt.set_interrupt::<3, _>(my_handler_a); - let addr_a = unsafe { idt.as_type_erased() }[3].handler_address(); + use crate::sync::LazyLock; + static IDT: LazyLock = + crate::sync::LazyLock::new(InterruptDescriptorTable::new_default); - serial_println!("idt: {:#?}", idt); + unsafe { IDT.load() }; - unsafe { - idt.load(); - } + super::instructions::int3(); // Trigger a breakpoint interrupt (interrupt 3) - super::instructions::int3(); - - serial_println!("back from int3"); - - idt.set_interrupt::<3, _>(my_handler_b); - let addr_b = unsafe { idt.as_type_erased() }[3].handler_address(); - assert_ne!(addr_a, addr_b, "Handler addresses should be different"); - - unsafe { - idt.load(); - } - - super::instructions::int3(); - - idt.set_interrupt::<3, _>(|frame, index, error_code| { - crate::serial_println!("handler c!"); - }); - - unsafe { - idt.load(); - } - - super::instructions::int3(); + serial_println!("Breakpoint interrupt handled successfully."); }