132 lines
2.8 KiB
Rust
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();
|
|
}
|
|
}
|
|
} |