#include "./handlers.h" #include "../arch/core_cr.h" #include "../arch/idt.h" #include "../arch/lapic.h" #include "../arch/system.h" #include "../debug/kernelpanic.h" #include "../debug/output.h" #include "../device/ps2controller.h" #include "./epilogues.h" #include "./guard.h" #include "../memory/pagetable.h" #include "../memory/pageframealloc.h" static void printContext(const InterruptContext *context) { DBG << "ip: " << hex << context->cs << ':' << context->ip << " sp: " << context->ss << ':' << context->sp << " flags" << bin << context->flags << endl; } [[gnu::interrupt]] static void handle_invalid_opcode( InterruptContext *context) { DBG << "Invalid opcode encountered" << endl; printContext(context); kernelpanic("Invalid opcode!"); } [[gnu::interrupt]] static void handle_double_fault(InterruptContext *context, uint64_t error) { DBG << "Double fault encountered. Error code: " << dec << error << endl; printContext(context); kernelpanic("Double fault!"); } [[gnu::interrupt]] static void handle_invalid_tss(InterruptContext *context, uint64_t error) { DBG << "Invalid tss encountered. Offending selector idx: " << dec << error << endl; printContext(context); kernelpanic("Invalid TSS!"); } [[gnu::interrupt]] static void handle_general_protection_fault( InterruptContext *context, uint64_t error) { DBG << "General protection fault encountered. Error code: " << dec << error << endl; printContext(context); kernelpanic("General protection fault!"); } #include "syscall/skeleton.h" [[gnu::interrupt]] static void handle_page_fault(InterruptContext *context, uint64_t error) { DBG << "Page fault encountered at linear address " << hex << Core::CR<2>::read() << endl << PageFaultError(error) << endl; four_lvl_paging_t* paging_tree = Guard::enter().vault().scheduler.active()->paging_tree ; asm volatile("mov %%cr3, %0" : "=r"(paging_tree)); uintptr_t virt = 0; asm volatile("mov %%cr2, %0" : "=r"(virt)); if (PageFaultError(error).present && PageFaultError(error).write) { uintptr_t pf =isMapped(virt, paging_tree); uint64_t pf_number = uint64_t (pf >> 12 ); if(PageFrameAllocator::PageFrames[pf_number].ref_count==1){ setMapping(virt, (void*) pf , paging_tree, true); }else{ uintptr_t page = (uintptr_t) PageFrameAllocator::alloc(false); //Syscall::Skeleton::map(page, 4096); setMapping(virt, (void*) page , paging_tree, true); memcpy( (void*)page, (void*)virt, 4096); Syscall::Skeleton::invlpg(virt); } } //Syscall::Skeleton::exit(Guard::enter().vault()); //kernelpanic("Page fault!"); } /*! \brief Assembly interrupt handler for the keyboard. * * On keyboard interrupt, the register state is saved to and restored from the * stack. This function wraps the handle_keyboard C-function. * */ extern "C" [[gnu::interrupt]] void handle_keyboard_asm( InterruptContext *context); /*! \brief Higher-level Interrupt handler for the keyboard. * * On keyboard interrupt, the PS2-Controller may contain a valid Key that has to * be fetched. * */ extern "C" void handle_keyboard() { // DBG_VERBOSE << "Keyboard interrupt" << endl; Key key; if (PS2Controller::fetch(key)) { // Ctrl-Alt-Delete should perform a reboot. This should still be done in // prologue, to ensure that rebooting still works reliably in case of // broken epilogues. if (key.ctrl() && key.alt() && key.scancode == Key::Scancode::KEY_DEL) { System::reboot(); } // Check if the last key was processed by the epilogue if (!Epilogues::key.valid()) { // Make sure we can receive new interrupts LAPIC::endOfInterrupt(); // Enqueue new epilogue Epilogues::key = key; Guard::relay(Epilogues::keyboard); return; } } LAPIC::endOfInterrupt(); } [[maybe_unused, gnu::interrupt]] static void handle_panic( InterruptContext *context) { (void)context; kernelpanic("Panic interrupt triggered!"); } [[maybe_unused, gnu::interrupt]] static void handle_timer( InterruptContext *context) { // DBG_VERBOSE << "Timer interrupt" << endl; (void)context; LAPIC::endOfInterrupt(); Guard::relay(Epilogues::timer); } void initInterruptHandlers() { // Some handlers that are useful for debugging IDT::set(Core::Interrupt::Vector::INVALID_OPCODE , IDT::InterruptDescriptor::Returning(handle_invalid_opcode)); IDT::set(Core::Interrupt::Vector::DOUBLE_FAULT , IDT::InterruptDescriptor::DivergingWithError(handle_double_fault)); IDT::set(Core::Interrupt::Vector::INVALID_TSS , IDT::InterruptDescriptor::DivergingWithError(handle_invalid_tss)); IDT::set(Core::Interrupt::Vector::GENERAL_PROTECTION_FAULT, IDT::InterruptDescriptor::DivergingWithError(handle_general_protection_fault)); IDT::set(Core::Interrupt::Vector::PAGE_FAULT , IDT::InterruptDescriptor::DivergingWithError(handle_page_fault)); // TODO: Add more handlers here IDT::set(Core::Interrupt::Vector::KEYBOARD, IDT::InterruptDescriptor::Returning(handle_keyboard_asm)); IDT::set(Core::Interrupt::Vector::PANIC, IDT::InterruptDescriptor::Returning(handle_panic)); IDT::set(Core::Interrupt::Vector::TIMER, IDT::InterruptDescriptor::Returning(handle_timer)); // Load the idt pointer IDT::load(); }