x86_interrupts 1.0.0

A Simple x86 Interrupt Library
Documentation
use crate::pic::*;
use lazy_static::lazy_static;
use x86_64::structures::{idt::{InterruptDescriptorTable, InterruptStackFrame}};
use spin::Mutex;
use x86_64::instructions::port::*;

const PIC1: u16 = 0x21;
const PIC2: u16 = 0xA1;

type BasicHandler = fn();
type BreakpointHandler = fn(u64, u64, u64);

lazy_static! {
    static ref DF_HANDLER : Mutex<BasicHandler> = Mutex::new(default_handler);
    static ref BP_HANDLER : Mutex<BreakpointHandler> = Mutex::new(default_bp_handler);
    static ref HANDLERS : Mutex<[BasicHandler; 16]> = Mutex::new([default_handler; 16]);

    static ref IDT: InterruptDescriptorTable = {
        let mut idt = InterruptDescriptorTable::new();
        idt.breakpoint.set_handler_fn(breakpoint_handler);
        set_handler!(idt, 0, irq_0);
        set_handler!(idt, 1, irq_1);
        set_handler!(idt, 2, irq_2);
        set_handler!(idt, 3, irq_3);
        set_handler!(idt, 4, irq_4);
        set_handler!(idt, 5, irq_5);
        set_handler!(idt, 6, irq_6);
        set_handler!(idt, 7, irq_7);
        set_handler!(idt, 8, irq_8);
        set_handler!(idt, 9, irq_9);
        set_handler!(idt, 10, irq_10);
        set_handler!(idt, 11, irq_11);
        set_handler!(idt, 12, irq_12);
        set_handler!(idt, 13, irq_13);
        set_handler!(idt, 14, irq_14);
        set_handler!(idt, 15, irq_15);
        idt
    };
}


fn default_handler() {

}

fn default_bp_handler(_ip: u64, _flags: u64, _cs: u64) {

} 

gen_interrupt_handler!(irq_0, 0);
gen_interrupt_handler!(irq_1, 1);
gen_interrupt_handler!(irq_2, 2);
gen_interrupt_handler!(irq_3, 3);
gen_interrupt_handler!(irq_4, 4);
gen_interrupt_handler!(irq_5, 5);
gen_interrupt_handler!(irq_6, 6);
gen_interrupt_handler!(irq_7, 7);
gen_interrupt_handler!(irq_8, 8);
gen_interrupt_handler!(irq_9, 9);
gen_interrupt_handler!(irq_10, 10);
gen_interrupt_handler!(irq_11, 11);
gen_interrupt_handler!(irq_12, 12);
gen_interrupt_handler!(irq_13, 13);
gen_interrupt_handler!(irq_14, 14);
gen_interrupt_handler!(irq_15, 15);

macro gen_interrupt_handler($name : ident, $irq : expr) {
    extern "x86-interrupt" fn $name(_ : InterruptStackFrame) {
        let handlers = HANDLERS.lock();
        handlers[$irq]();
        unsafe { notify_end_of_interrupt(index($irq)) }
    }
}

macro set_handler($idt : ident, $irq : expr, $handler : ident) {
    $idt[index($irq) as usize].set_handler_fn($handler);
}

pub(crate) fn set_basic_handler(irq : u8, handler : BasicHandler) {
    HANDLERS.lock()[index(irq) as usize] = handler;
}

pub(crate) fn index(irq : u8) -> u8 {
    pic_1_offset() + irq
}

pub(crate) fn set_irq_mask(irq: u8) {
    let mut port: Port<u8> = Port::new(if irq < 8 { PIC1 } else { PIC2 });
    unsafe {
        let value = port.read() | (1 << (if irq < 8 { irq } else { irq - 8 }));
        port.write(value);
    }
}

pub(crate) fn clear_irq_mask(irq: u8) {
    let mut port: Port<u8> = Port::new(if irq < 8 { PIC1 } else { PIC2 });
    unsafe {
        let value = port.read() & !(1 << if irq < 8 { irq } else { irq - 8 });
        port.write(value);
    }
}
extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {
    BP_HANDLER.lock()(stack_frame.instruction_pointer.as_u64(), stack_frame.cpu_flags, stack_frame.code_segment);
}

#[allow(dead_code)]
extern "x86-interrupt" fn double_fault_handler(_stack_frame: InterruptStackFrame, _error_code: u64) -> ! {
    DF_HANDLER.lock()();
    panic!("Double Fault Exception");
}