use core::arch::global_asm;
use core::cell::LazyCell;
use core::usize;
use bitfield_struct::bitfield;
use crate::arch::gdt::Ring;
use crate::arch::int::idt::*;
use crate::arch::{cpu, int};
use crate::arch::regs::Cr2;
use crate::device::KEYBOARD;
use super::super::gdt::GDT;
use super::epilog::Epilog;
use super::guard::GUARD;
use super::Vector;
static mut IDT: LazyCell<InterruptDescriptorTable> = LazyCell::new(|| {
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);
let opt = idt[Vector::Syscall as _].set_handler_fn(syscall_trampoline);
opt.set_privilege_level(Ring::User);
idt
});
pub fn load() {
unsafe { 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);
}
extern "x86-interrupt" fn general_protection_fault(stack: InterruptStack, error: u32) {
#[bitfield(u32)]
struct SelectorError {
external: bool,
#[bits(2)]
table: u8,
#[bits(13)]
index: usize,
#[bits(16)]
__: (),
}
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 *const u8;
panic!("PAGE FAULT {error:?} to {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(Epilog::Timer);
}
extern "x86-interrupt" fn keyboard(_stack: InterruptStack) {
let hit = unsafe { KEYBOARD.key_hit() };
super::eoi(Vector::Keyboard as _);
if let Some(key) = hit {
GUARD.relay(Epilog::Keyboard { key });
}
}
extern "x86-interrupt" fn assassin(_stack: InterruptStack) {
super::eoi(Vector::Assassin as _);
println!(dbg: "{}: assassin", cpu::id());
GUARD.relay(Epilog::Assassin);
}
extern "x86-interrupt" fn wake_up(_stack: InterruptStack) {
super::eoi(Vector::WakeUp as _);
int::enable(true);
}
int_wrapper!(syscall, syscall_trampoline);
#[no_mangle]
pub extern "C" fn syscall(_context: &mut InterruptContext) {
todo!("A1: Syscalls")
}