use core::arch::naked_asm;
use bitfield_struct::bitfield;
use pc_keyboard::DecodedKey;
use super::super::gdt::GDT;
use super::epilogue::Epilogue;
use super::guard::GUARD;
use super::Vector;
use crate::arch::int::idt::*;
use crate::arch::regs::Cr2;
use crate::arch::{cpu, int};
use crate::device::KEYBOARD;
use crate::util::Once;
static IDT: Once<InterruptDescriptorTable> = Once::new();
pub fn load() {
IDT.get_or_init(|| {
let mut idt = InterruptDescriptorTable::new();
idt.double_fault.set_handler_fn(double_fault);
idt.general_protection_fault
.set_handler_fn(general_protection_fault);
idt.page_fault.set_handler_fn(page_fault);
idt.invalid_tss.set_handler_fn(invalid_tss);
idt[Vector::Timer as _].set_handler_fn(timer);
idt[Vector::Keyboard as _].set_handler_fn(keyboard);
idt[Vector::WakeUp as _].set_handler_fn(wake_up);
idt[Vector::Assassin as _].set_handler_fn(assassin);
idt[Vector::Panic as _].set_handler_fn(panic);
idt
})
.activate();
}
extern "x86-interrupt" fn double_fault(stack: InterruptStack, error: u32) -> ! {
panic!("DOUBLE FAULT {error:x}\n{:#x?}", stack);
}
extern "x86-interrupt" fn invalid_tss(stack: InterruptStack, error: u32) {
panic!("TSS {error:x}\n{:#x?}", stack);
}
#[bitfield(u32)]
struct SelectorError {
external: bool,
#[bits(2)]
table: u8,
#[bits(13)]
index: usize,
#[bits(16)]
__: (),
}
extern "x86-interrupt" fn general_protection_fault(stack: InterruptStack, error: u32) {
unsafe {
serial!("{:?}", GUARD.read().scheduler.active());
serial!("GDT: {:x?}", GDT.0.map(u64::from));
}
panic!(
"GENERAL PROTECTION FAULT {:?}\n{stack:#x?}",
SelectorError(error),
);
}
extern "x86-interrupt" fn page_fault(stack: InterruptStack, error: PageFaultError) {
let vaddr = Cr2::read().0 as *mut u8;
panic!("PAGE FAULT {error:?} at {vaddr:?} @ {stack:#x?}");
}
extern "x86-interrupt" fn panic(stack: InterruptStack) {
panic!("PANIC\n{:#?}", stack);
}
extern "x86-interrupt" fn timer(_stack: InterruptStack) {
super::eoi(Vector::Timer as _);
GUARD.relay(Epilogue::Timer);
}
extern "x86-interrupt" fn keyboard(_stack: InterruptStack) {
let event = unsafe { KEYBOARD.event() };
super::eoi(Vector::Keyboard as _);
if let Some(DecodedKey::Unicode(key)) = event {
GUARD.relay(Epilogue::Keyboard { key });
}
}
extern "x86-interrupt" fn assassin(_stack: InterruptStack) {
super::eoi(Vector::Assassin as _);
debug!("{}: assassin", cpu::id());
GUARD.relay(Epilogue::Assassin);
}
extern "x86-interrupt" fn wake_up(_stack: InterruptStack) {
super::eoi(Vector::WakeUp as _);
int::enable(true);
}
#[derive(Debug)]
pub struct SyscallStack {
pub stack: InterruptStack,
}
#[naked]
#[no_mangle]
pub unsafe extern "x86-interrupt" fn syscall_trampoline(stack: InterruptStack) {
naked_asm!(
"push esp",
"call {syscall}",
"add esp, 4",
"iretd",
syscall = sym syscall
)
}
#[no_mangle]
pub extern "C" fn syscall(_context: &mut SyscallStack) {
todo!("BST B1 - Implement syscalls")
}