Files
bsb2/kernel/interrupt/handlers.cc
Niklas Gollenstede 174fe17e89 Handout
2025-10-31 22:37:36 +01:00

135 lines
4.3 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"
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!");
}
[[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;
printContext(context);
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::ReturningWithError(handle_invalid_tss));
IDT::set(Core::Interrupt::Vector::GENERAL_PROTECTION_FAULT,
IDT::InterruptDescriptor::ReturningWithError(
handle_general_protection_fault));
IDT::set(Core::Interrupt::Vector::PAGE_FAULT,
IDT::InterruptDescriptor::ReturningWithError(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();
}