160 lines
5.2 KiB
C++
160 lines
5.2 KiB
C++
#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();
|
|
}
|