mxrox/src/kernel/irq.rs

132 lines
2.8 KiB
Rust

use core::ptr::write_volatile;
use core::arch::asm;
const APIC_BASE: u32 = 0xFEE00000;
const APIC_EOI: u32 = APIC_BASE + 0x0B0;
const APIC_SVR: u32 = APIC_BASE + 0x0F0;
const PIC1_CMD: u16 = 0x20;
const PIC1_DATA: u16 = 0x21;
const PIC2_CMD: u16 = 0xA0;
const PIC2_DATA: u16 = 0xA1;
const ICW1_INIT: u8 = 0x10;
const ICW1_ICW4: u8 = 0x01;
const ICW4_8086: u8 = 0x01;
const PIC_EOI: u8 = 0x20; /* End-of-interrupt command code */
const APIC_ENABLED: bool = false;
#[repr(C, packed)]
#[derive(Clone, Copy)]
pub struct IdtEntry {
offset_low: u16,
selector: u16,
ist: u8,
type_attr: u8,
offset_middle: u16
}
pub const IDT_SIZE: usize = 256;
#[repr(C)]
pub struct Idt {
entries: [IdtEntry; IDT_SIZE],
}
static mut IDT: Idt = Idt {
entries: [IdtEntry {
offset_low: 0,
selector: 0,
ist: 0,
type_attr: 0,
offset_middle: 0,
}; IDT_SIZE],
};
unsafe fn is_apic_available() -> bool {
if !APIC_ENABLED {
return false;
}
let edx: u32;
asm!(
"cpuid",
inout("eax") 1 => _,
lateout("edx") edx
);
(edx & (1 << 9)) != 0
}
unsafe fn init_idt() {
asm!("lidt [{}]", "sti", in(reg) &IDT as *const _);
}
unsafe fn init_apic() {
write_volatile(APIC_SVR as *mut u32, 0x100 | 0x1);
}
unsafe fn send_apic_eoi() {
write_volatile(APIC_EOI as *mut u32, 0);
}
unsafe fn send_pic_eoi(irq: usize) {
if irq >= 8 { write_volatile(PIC2_CMD as *mut u8, PIC_EOI); }
write_volatile(PIC1_CMD as *mut u8, PIC_EOI);
}
unsafe fn init_pic() {
write_volatile(PIC1_CMD as *mut u8, ICW1_INIT | ICW1_ICW4);
write_volatile(PIC2_CMD as *mut u8, ICW1_INIT | ICW1_ICW4);
write_volatile(PIC1_DATA as *mut u8, 0x20);
write_volatile(PIC2_DATA as *mut u8, 0x28);
write_volatile(PIC1_DATA as *mut u8, 4);
write_volatile(PIC2_DATA as *mut u8, 2);
write_volatile(PIC1_DATA as *mut u8, ICW4_8086);
write_volatile(PIC2_DATA as *mut u8, ICW4_8086);
write_volatile(PIC1_DATA as *mut u8, 0xFB);
write_volatile(PIC2_DATA as *mut u8, 0xFF);
}
pub fn send_eoi(irq: usize) {
unsafe {
if is_apic_available() {
send_apic_eoi()
} else {
send_pic_eoi(irq)
}
}
}
/// all interrupt vectors you can find here: https://wiki.osdev.org/Interrupt_Vector_Table
pub fn register_idt(handler: u32, int_vec: u8) {
unsafe {
let entry = &mut IDT.entries[int_vec as usize];
entry.offset_low = handler as u16;
entry.selector = 0x08;
entry.ist = 0;
entry.type_attr = 0x8E;
entry.offset_middle = (handler >> 16) as u16;
}
}
pub fn init_interrupts() {
unsafe {
init_idt();
if is_apic_available() {
init_apic();
} else {
init_pic();
}
}
}