Initial work on paging, also complete ish interrupt registration
This commit is contained in:
@@ -159,7 +159,7 @@ impl Flags {
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct GdtSelector {
|
||||
inner: u16,
|
||||
}
|
||||
|
||||
@@ -1,38 +1,68 @@
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use crate::gdt::{DPL, GdtSelector};
|
||||
|
||||
pub mod vectors;
|
||||
|
||||
#[repr(C, packed)]
|
||||
#[must_use]
|
||||
pub struct InterruptTableDescriptor {
|
||||
size: u16,
|
||||
offset: u64,
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, Copy)]
|
||||
#[must_use]
|
||||
pub struct IdtTableEntry {
|
||||
inner: u128,
|
||||
}
|
||||
|
||||
pub type ISR = extern "x86-interrupt" fn(InterruptStackFrame) -> ();
|
||||
pub type ISRWithIdx = extern "x86-interrupt" fn(InterruptStackFrame, u64) -> ();
|
||||
pub type ISRWithIdxNeverReturns = extern "x86-interrupt" fn(InterruptStackFrame, u64) -> !;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
#[must_use]
|
||||
pub struct InterruptStackFrame {
|
||||
ip: usize,
|
||||
cs: usize,
|
||||
flags: usize,
|
||||
sp: usize,
|
||||
ss: usize,
|
||||
pub ip: usize,
|
||||
pub cs: usize,
|
||||
pub flags: usize,
|
||||
pub sp: usize,
|
||||
pub ss: usize,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[must_use]
|
||||
pub enum Gate {
|
||||
Interrupt = 0b1110,
|
||||
Trap = 0b1111,
|
||||
}
|
||||
|
||||
impl IdtTableEntry {
|
||||
pub fn new(isr: ISR, selector: GdtSelector, ist: u8, gate: Gate, priority: DPL) -> Self {
|
||||
let mut inner = 0b0;
|
||||
let offset = (isr as *const ()) as u64;
|
||||
#[repr(u8)]
|
||||
#[must_use]
|
||||
pub enum Ist {
|
||||
Idx0 = 0,
|
||||
Idx1 = 1,
|
||||
Idx2 = 2,
|
||||
Idx3 = 3,
|
||||
Idx4 = 4,
|
||||
Idx5 = 5,
|
||||
Idx6 = 6,
|
||||
Idx7 = 7,
|
||||
}
|
||||
|
||||
impl IdtTableEntry {
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
const fn build(
|
||||
offset: u64,
|
||||
selector: GdtSelector,
|
||||
ist: Ist,
|
||||
gate: Gate,
|
||||
priority: DPL,
|
||||
) -> Self {
|
||||
let mut inner = 0;
|
||||
let bytes = (offset >> 32) as u32;
|
||||
inner |= (bytes as u128) << 64;
|
||||
|
||||
@@ -44,8 +74,6 @@ impl IdtTableEntry {
|
||||
|
||||
inner |= (selector.raw() as u128) << 16;
|
||||
|
||||
assert!(ist <= 0b111);
|
||||
|
||||
inner |= (ist as u128) << 32;
|
||||
inner |= (gate as u128) << 40;
|
||||
inner |= (priority as u128) << 45;
|
||||
@@ -53,4 +81,98 @@ impl IdtTableEntry {
|
||||
|
||||
Self { inner }
|
||||
}
|
||||
|
||||
pub const fn null() -> Self {
|
||||
Self { inner: 0 }
|
||||
}
|
||||
|
||||
pub fn new(isr: ISR, selector: GdtSelector, ist: Ist, gate: Gate, priority: DPL) -> Self {
|
||||
let offset = (isr as *const ()) as u64;
|
||||
Self::build(offset, selector, ist, gate, priority)
|
||||
}
|
||||
|
||||
// TODO: Make the type system check ist valid here.
|
||||
pub fn with_idx(
|
||||
isr: ISRWithIdx,
|
||||
selector: GdtSelector,
|
||||
ist: Ist,
|
||||
gate: Gate,
|
||||
priority: DPL,
|
||||
) -> Self {
|
||||
let offset = (isr as *const ()) as u64;
|
||||
Self::build(offset, selector, ist, gate, priority)
|
||||
}
|
||||
}
|
||||
|
||||
static mut IDT: [IdtTableEntry; 256] = [IdtTableEntry::null(); _];
|
||||
static ASSIGNED: [AtomicBool; 256] = [const { AtomicBool::new(false) }; 256];
|
||||
#[allow(static_mut_refs)]
|
||||
const IDT_SIZE: u16 = unsafe { (core::mem::size_of_val(&IDT) - 1) as u16 };
|
||||
static IDT_INITIATED: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
#[must_use]
|
||||
pub struct Idt<const TABLE_SPECIFIED: bool>;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[must_use]
|
||||
pub enum Error {
|
||||
InvalidVectorIndex,
|
||||
VectorAlreadyAssigned,
|
||||
}
|
||||
|
||||
impl<const TABLE_SPECIFIED: bool> Idt<TABLE_SPECIFIED> {
|
||||
/// Registers a new handler
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is safe assuming that this is the only [`Idt`] that exists. This assumption
|
||||
/// holds given that the user does not forcibly create one.
|
||||
pub fn register_handler(
|
||||
&mut self,
|
||||
vector: usize,
|
||||
entry: IdtTableEntry,
|
||||
) -> Result<&mut Self, Error> {
|
||||
if vector >= ASSIGNED.len() {
|
||||
return Err(Error::InvalidVectorIndex);
|
||||
}
|
||||
|
||||
if ASSIGNED[vector].swap(true, Ordering::AcqRel) {
|
||||
return Err(Error::VectorAlreadyAssigned);
|
||||
}
|
||||
|
||||
unsafe { IDT[vector] = entry };
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
#[allow(static_mut_refs)]
|
||||
fn table(&self) -> InterruptTableDescriptor {
|
||||
let addr = unsafe { IDT.as_ptr() as *const _ as u64 };
|
||||
InterruptTableDescriptor {
|
||||
size: IDT_SIZE,
|
||||
offset: addr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Idt<false> {
|
||||
pub fn set_table(self) -> Idt<true> {
|
||||
let ptr = self.table();
|
||||
unsafe {
|
||||
core::arch::asm!(
|
||||
"lidt [{}]",
|
||||
in(reg) &ptr,
|
||||
options(readonly,nostack,preserves_flags)
|
||||
)
|
||||
}
|
||||
Idt
|
||||
}
|
||||
|
||||
pub fn new() -> Self {
|
||||
assert!(
|
||||
!IDT_INITIATED.swap(true, Ordering::AcqRel),
|
||||
"IDT already initiated"
|
||||
);
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
73
x86_drivers/src/idt/vectors.rs
Normal file
73
x86_drivers/src/idt/vectors.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
use crate::idt::{
|
||||
DPL, Error, Gate, GdtSelector, ISR, ISRWithIdx, ISRWithIdxNeverReturns, Idt, IdtTableEntry, Ist,
|
||||
};
|
||||
|
||||
macro_rules! vector {
|
||||
($(
|
||||
$(~$idx_:literal)?
|
||||
$($idx:literal: $name:ident => $type:ty)?
|
||||
);*) => {
|
||||
pub trait Vector {
|
||||
type FunctionSignature;
|
||||
const IDX:usize;
|
||||
fn register_handler<const REGISTERD:bool>(table:&mut Idt<REGISTERD>, isr: Self::FunctionSignature, selector: GdtSelector, ist: Ist, gate: Gate, priority: DPL) -> Result<&mut Idt<REGISTERD>,Error>;
|
||||
}
|
||||
|
||||
pub mod named_isr {
|
||||
$(
|
||||
$(pub struct $name;)?
|
||||
)*
|
||||
}
|
||||
|
||||
$(
|
||||
$(
|
||||
impl Vector for named_isr::$name {
|
||||
type FunctionSignature = $type;
|
||||
const IDX:usize = $idx;
|
||||
|
||||
fn register_handler<const REGISTERD:bool>(table:&mut Idt<REGISTERD>, isr: Self::FunctionSignature, selector: GdtSelector, ist: Ist, gate: Gate, priority: DPL) -> Result<&mut Idt<REGISTERD>,Error> {
|
||||
let offset = (isr as *const ()) as u64;
|
||||
let desc = IdtTableEntry::build(offset, selector, ist, gate, priority);
|
||||
table.register_handler(Self::IDX, desc)
|
||||
}
|
||||
}
|
||||
)?
|
||||
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
vector!(
|
||||
0: DivisionError => ISR;
|
||||
1: Debug => ISR;
|
||||
2: NonMaskableInterrupt => ISR;
|
||||
3: Breakpoint => ISR;
|
||||
4: Overflow => ISR;
|
||||
5: BoundRangeExceeded => ISR;
|
||||
6: InvalidOpcode => ISR;
|
||||
7: DeviceNotAvailable => ISR;
|
||||
8: DoubleFault => ISRWithIdxNeverReturns;
|
||||
9: CoprocessorSegmentOverrun => ISR;
|
||||
10: InvalidTSS => ISRWithIdx;
|
||||
11: SegmentNotPresent => ISRWithIdx;
|
||||
12: StackSegmentFault => ISRWithIdx;
|
||||
13: GeneralProtectionFault => ISRWithIdx;
|
||||
14: PageFault => ISRWithIdx;
|
||||
~15;
|
||||
16: X87FloatingPointException => ISR;
|
||||
17: AlignmentCheck => ISRWithIdx;
|
||||
18: MachineCheck => ISR;
|
||||
19: SIMDFloatingPointException => ISR;
|
||||
20: VirtualizationException => ISR;
|
||||
21: ControlProtectionException => ISRWithIdx;
|
||||
~22;
|
||||
~23;
|
||||
~24;
|
||||
~25;
|
||||
~26;
|
||||
~27;
|
||||
28: HypervisorInjectionException => ISR;
|
||||
29: VMMCommunicationException => ISRWithIdx;
|
||||
30: SecurityException => ISRWithIdx;
|
||||
~31;
|
||||
);
|
||||
@@ -23,7 +23,8 @@
|
||||
clippy::unused_self,
|
||||
clippy::must_use_candidate,
|
||||
clippy::new_without_default,
|
||||
clippy::cast_possible_truncation
|
||||
clippy::cast_possible_truncation,
|
||||
clippy::missing_errors_doc
|
||||
)]
|
||||
pub mod uart;
|
||||
|
||||
@@ -38,5 +39,7 @@ mod private {
|
||||
|
||||
pub mod prelude {
|
||||
pub use crate::core::Core;
|
||||
pub use crate::idt::vectors::*;
|
||||
pub use crate::idt::*;
|
||||
pub use crate::uart::{InitUart, Uart};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user