moros/src/kernel/idt.rs

110 lines
3.7 KiB
Rust

use crate::{print, kernel};
use lazy_static::lazy_static;
use spin::Mutex;
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
use x86_64::instructions::interrupts;
// Translate IRQ into system interrupt
fn interrupt_index(irq: u8) -> u8 {
kernel::pic::PIC_1_OFFSET + irq
}
fn default_handler() {
return;
}
macro_rules! irq_handler {
($handler:ident, $irq:expr) => {
pub extern "x86-interrupt" fn $handler(_stack_frame: &mut InterruptStackFrame) {
let handlers = IRQ_HANDLERS.lock();
handlers[$irq]();
unsafe { kernel::pic::PICS.lock().notify_end_of_interrupt(interrupt_index($irq)); }
}
};
}
irq_handler!(irq0_handler, 0);
irq_handler!(irq1_handler, 1);
irq_handler!(irq2_handler, 2);
irq_handler!(irq3_handler, 3);
irq_handler!(irq4_handler, 4);
irq_handler!(irq5_handler, 5);
irq_handler!(irq6_handler, 6);
irq_handler!(irq7_handler, 7);
irq_handler!(irq8_handler, 8);
irq_handler!(irq9_handler, 9);
irq_handler!(irq10_handler, 10);
irq_handler!(irq11_handler, 11);
irq_handler!(irq12_handler, 12);
irq_handler!(irq13_handler, 13);
irq_handler!(irq14_handler, 14);
irq_handler!(irq15_handler, 15);
lazy_static! {
pub static ref IRQ_HANDLERS: Mutex<[fn(); 16]> = Mutex::new([default_handler; 16]);
static ref IDT: InterruptDescriptorTable = {
let mut idt = InterruptDescriptorTable::new();
idt.breakpoint.set_handler_fn(breakpoint_handler);
unsafe {
idt.double_fault.set_handler_fn(double_fault_handler).set_stack_index(kernel::gdt::DOUBLE_FAULT_IST_INDEX);
}
idt[interrupt_index(0) as usize].set_handler_fn(irq0_handler);
idt[interrupt_index(1) as usize].set_handler_fn(irq1_handler);
idt[interrupt_index(2) as usize].set_handler_fn(irq2_handler);
idt[interrupt_index(3) as usize].set_handler_fn(irq3_handler);
idt[interrupt_index(4) as usize].set_handler_fn(irq4_handler);
idt[interrupt_index(5) as usize].set_handler_fn(irq5_handler);
idt[interrupt_index(6) as usize].set_handler_fn(irq6_handler);
idt[interrupt_index(7) as usize].set_handler_fn(irq7_handler);
idt[interrupt_index(8) as usize].set_handler_fn(irq8_handler);
idt[interrupt_index(9) as usize].set_handler_fn(irq9_handler);
idt[interrupt_index(10) as usize].set_handler_fn(irq10_handler);
idt[interrupt_index(11) as usize].set_handler_fn(irq11_handler);
idt[interrupt_index(12) as usize].set_handler_fn(irq12_handler);
idt[interrupt_index(13) as usize].set_handler_fn(irq13_handler);
idt[interrupt_index(14) as usize].set_handler_fn(irq14_handler);
idt[interrupt_index(15) as usize].set_handler_fn(irq15_handler);
idt
};
}
pub fn init() {
IDT.load();
}
use x86_64::instructions::port::Port;
pub fn set_irq_handler(irq: u8, handler: fn()) {
interrupts::without_interrupts(|| {
let mut handlers = IRQ_HANDLERS.lock();
handlers[irq as usize] = handler;
clear_irq_mask(irq);
});
}
pub fn set_irq_mask(irq: u8) {
let mut port: Port<u8> = Port::new(if irq < 8 { 0x21 } else { 0xA1 } );
unsafe {
let value = port.read() & (1 << irq);
port.write(value);
}
}
pub fn clear_irq_mask(irq: u8) {
let mut port: Port<u8> = Port::new(if irq < 8 { 0x21 } else { 0xA1 } );
unsafe {
let value = port.read() & !(1 << irq);
port.write(value);
}
}
extern "x86-interrupt" fn breakpoint_handler(stack_frame: &mut InterruptStackFrame) {
print!("EXCEPTION: BREAKPOINT\n{:#?}\n", stack_frame);
}
extern "x86-interrupt" fn double_fault_handler(stack_frame: &mut InterruptStackFrame, _error_code: u64) -> ! {
panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
}