use crate::sys; use crate::sys::process::Registers; use core::arch::asm; use lazy_static::lazy_static; use spin::Mutex; use x86_64::instructions::interrupts; use x86_64::instructions::port::Port; use x86_64::registers::control::Cr2; use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, InterruptStackFrameValue, PageFaultErrorCode}; const PIC1: u16 = 0x21; const PIC2: u16 = 0xA1; pub fn init() { IDT.load(); } // Translate IRQ into system interrupt fn interrupt_index(irq: u8) -> u8 { sys::pic::PIC_1_OFFSET + irq } fn default_irq_handler() {} lazy_static! { pub static ref IRQ_HANDLERS: Mutex<[fn(); 16]> = Mutex::new([default_irq_handler; 16]); static ref IDT: InterruptDescriptorTable = { let mut idt = InterruptDescriptorTable::new(); idt.breakpoint.set_handler_fn(breakpoint_handler); idt.stack_segment_fault.set_handler_fn(stack_segment_fault_handler); idt.segment_not_present.set_handler_fn(segment_not_present_handler); unsafe { idt.double_fault. set_handler_fn(double_fault_handler). set_stack_index(sys::gdt::DOUBLE_FAULT_IST_INDEX); idt.page_fault. set_handler_fn(page_fault_handler). set_stack_index(sys::gdt::PAGE_FAULT_IST_INDEX); idt.general_protection_fault. set_handler_fn(general_protection_fault_handler). set_stack_index(sys::gdt::GENERAL_PROTECTION_FAULT_IST_INDEX); idt[0x80]. set_handler_fn(core::mem::transmute(wrapped_syscall_handler as *mut fn())). //set_stack_index(sys::gdt::GENERAL_PROTECTION_FAULT_IST_INDEX). set_privilege_level(x86_64::PrivilegeLevel::Ring3); } idt[interrupt_index(0) as usize].set_handler_fn(irq0_handler); idt[interrupt_index(1) as usize].set_handler_fn(irq1_handler); idt[interrupt_index(2) as usize].set_handler_fn(irq2_handler); idt[interrupt_index(3) as usize].set_handler_fn(irq3_handler); idt[interrupt_index(4) as usize].set_handler_fn(irq4_handler); idt[interrupt_index(5) as usize].set_handler_fn(irq5_handler); idt[interrupt_index(6) as usize].set_handler_fn(irq6_handler); idt[interrupt_index(7) as usize].set_handler_fn(irq7_handler); idt[interrupt_index(8) as usize].set_handler_fn(irq8_handler); idt[interrupt_index(9) as usize].set_handler_fn(irq9_handler); idt[interrupt_index(10) as usize].set_handler_fn(irq10_handler); idt[interrupt_index(11) as usize].set_handler_fn(irq11_handler); idt[interrupt_index(12) as usize].set_handler_fn(irq12_handler); idt[interrupt_index(13) as usize].set_handler_fn(irq13_handler); idt[interrupt_index(14) as usize].set_handler_fn(irq14_handler); idt[interrupt_index(15) as usize].set_handler_fn(irq15_handler); idt }; } macro_rules! irq_handler { ($handler:ident, $irq:expr) => { pub extern "x86-interrupt" fn $handler(_stack_frame: InterruptStackFrame) { let handlers = IRQ_HANDLERS.lock(); handlers[$irq](); unsafe { sys::pic::PICS.lock().notify_end_of_interrupt(interrupt_index($irq)); } } }; } irq_handler!(irq0_handler, 0); irq_handler!(irq1_handler, 1); irq_handler!(irq2_handler, 2); irq_handler!(irq3_handler, 3); irq_handler!(irq4_handler, 4); irq_handler!(irq5_handler, 5); irq_handler!(irq6_handler, 6); irq_handler!(irq7_handler, 7); irq_handler!(irq8_handler, 8); irq_handler!(irq9_handler, 9); irq_handler!(irq10_handler, 10); irq_handler!(irq11_handler, 11); irq_handler!(irq12_handler, 12); irq_handler!(irq13_handler, 13); irq_handler!(irq14_handler, 14); irq_handler!(irq15_handler, 15); extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) { debug!("EXCEPTION: BREAKPOINT"); debug!("Stack Frame: {:#?}", stack_frame); panic!(); } extern "x86-interrupt" fn double_fault_handler(stack_frame: InterruptStackFrame, error_code: u64) -> ! { debug!("EXCEPTION: DOUBLE FAULT"); debug!("Stack Frame: {:#?}", stack_frame); debug!("Error: {:?}", error_code); panic!(); } extern "x86-interrupt" fn page_fault_handler(_stack_frame: InterruptStackFrame, _error_code: PageFaultErrorCode) { let addr = Cr2::read().as_u64(); sys::allocator::alloc_pages(addr, 1); } extern "x86-interrupt" fn general_protection_fault_handler(stack_frame: InterruptStackFrame, error_code: u64) { debug!("EXCEPTION: GENERAL PROTECTION FAULT"); debug!("Stack Frame: {:#?}", stack_frame); debug!("Error: {:?}", error_code); panic!(); } extern "x86-interrupt" fn stack_segment_fault_handler(stack_frame: InterruptStackFrame, error_code: u64) { debug!("EXCEPTION: STACK SEGMENT FAULT"); debug!("Stack Frame: {:#?}", stack_frame); debug!("Error: {:?}", error_code); panic!(); } extern "x86-interrupt" fn segment_not_present_handler(stack_frame: InterruptStackFrame, error_code: u64) { debug!("EXCEPTION: SEGMENT NOT PRESENT"); debug!("Stack Frame: {:#?}", stack_frame); debug!("Error: {:?}", error_code); panic!(); } // Naked function wrapper saving all scratch registers to the stack // See: https://os.phil-opp.com/returning-from-exceptions/#a-naked-wrapper-function macro_rules! wrap { ($fn: ident => $w:ident) => { #[naked] pub unsafe extern "sysv64" fn $w() { asm!( "push rax", "push rcx", "push rdx", "push rsi", "push rdi", "push r8", "push r9", "push r10", "push r11", "mov rsi, rsp", // Arg #2: register list "mov rdi, rsp", // Arg #1: interupt frame "add rdi, 9 * 8", "call {}", "pop r11", "pop r10", "pop r9", "pop r8", "pop rdi", "pop rsi", "pop rdx", "pop rcx", "pop rax", "iretq", sym $fn, options(noreturn) ); } }; } wrap!(syscall_handler => wrapped_syscall_handler); // NOTE: We can't use "x86-interrupt" for syscall_handler because we need to // return a result in the RAX register and it will be overwritten when the // context of the caller is restored. extern "sysv64" fn syscall_handler(stack_frame: &mut InterruptStackFrame, regs: &mut Registers) { // The registers order follow the System V ABI convention let n = regs.rax; let arg1 = regs.rdi; let arg2 = regs.rsi; let arg3 = regs.rdx; let arg4 = regs.r8; if n == sys::syscall::number::SPAWN { // Backup CPU context sys::process::set_stack_frame(**stack_frame); sys::process::set_registers(*regs); } let res = sys::syscall::dispatcher(n, arg1, arg2, arg3, arg4); if n == sys::syscall::number::EXIT { // Restore CPU context let sf = sys::process::stack_frame(); unsafe { //stack_frame.as_mut().write(sf); core::ptr::write_volatile(stack_frame.as_mut().extract_inner() as *mut InterruptStackFrameValue, sf); // FIXME core::ptr::write_volatile(regs, sys::process::registers()); } } regs.rax = res; unsafe { sys::pic::PICS.lock().notify_end_of_interrupt(0x80) }; } pub fn set_irq_handler(irq: u8, handler: fn()) { interrupts::without_interrupts(|| { let mut handlers = IRQ_HANDLERS.lock(); handlers[irq as usize] = handler; clear_irq_mask(irq); }); } pub fn set_irq_mask(irq: u8) { let mut port: Port = 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 fn clear_irq_mask(irq: u8) { let mut port: Port = Port::new(if irq < 8 { PIC1 } else { PIC2 }); unsafe { let value = port.read() & !(1 << if irq < 8 { irq } else { irq - 8 }); port.write(value); } }