summaryrefslogtreecommitdiff
path: root/Kernel/Arch/x86/common/Interrupts.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Kernel/Arch/x86/common/Interrupts.cpp')
-rw-r--r--Kernel/Arch/x86/common/Interrupts.cpp737
1 files changed, 737 insertions, 0 deletions
diff --git a/Kernel/Arch/x86/common/Interrupts.cpp b/Kernel/Arch/x86/common/Interrupts.cpp
new file mode 100644
index 0000000000..bcd5e5e663
--- /dev/null
+++ b/Kernel/Arch/x86/common/Interrupts.cpp
@@ -0,0 +1,737 @@
+/*
+ * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <AK/Format.h>
+#include <AK/Types.h>
+
+#include <Kernel/Interrupts/GenericInterruptHandler.h>
+#include <Kernel/Interrupts/SharedIRQHandler.h>
+#include <Kernel/Interrupts/SpuriousInterruptHandler.h>
+#include <Kernel/Interrupts/UnhandledInterruptHandler.h>
+#include <Kernel/Panic.h>
+#include <Kernel/PerformanceManager.h>
+#include <Kernel/Process.h>
+#include <Kernel/Random.h>
+#include <Kernel/Thread.h>
+
+#include <LibC/mallocdefs.h>
+
+#include <Kernel/Arch/x86/ISRStubs.h>
+#include <Kernel/Arch/x86/Processor.h>
+#include <Kernel/Arch/x86/RegisterState.h>
+#include <Kernel/Arch/x86/TrapFrame.h>
+
+extern FlatPtr start_of_unmap_after_init;
+extern FlatPtr end_of_unmap_after_init;
+extern FlatPtr start_of_ro_after_init;
+extern FlatPtr end_of_ro_after_init;
+
+namespace Kernel {
+
+READONLY_AFTER_INIT static DescriptorTablePointer s_idtr;
+READONLY_AFTER_INIT static IDTEntry s_idt[256];
+
+static GenericInterruptHandler* s_interrupt_handler[GENERIC_INTERRUPT_HANDLERS_COUNT];
+
+static EntropySource s_entropy_source_interrupts { EntropySource::Static::Interrupts };
+
+// clang-format off
+
+#if ARCH(I386)
+#define EH_ENTRY(ec, title) \
+ extern "C" void title##_asm_entry(); \
+ extern "C" void title##_handler(TrapFrame*) __attribute__((used)); \
+ asm( \
+ ".globl " #title "_asm_entry\n" \
+ "" #title "_asm_entry: \n" \
+ " pusha\n" \
+ " pushl %ds\n" \
+ " pushl %es\n" \
+ " pushl %fs\n" \
+ " pushl %gs\n" \
+ " pushl %ss\n" \
+ " mov $" __STRINGIFY(GDT_SELECTOR_DATA0) ", %ax\n" \
+ " mov %ax, %ds\n" \
+ " mov %ax, %es\n" \
+ " mov $" __STRINGIFY(GDT_SELECTOR_PROC) ", %ax\n" \
+ " mov %ax, %fs\n" \
+ " pushl %esp \n" /* set TrapFrame::regs */ \
+ " subl $" __STRINGIFY(TRAP_FRAME_SIZE - 4) ", %esp \n" \
+ " pushl %esp \n" \
+ " cld\n" \
+ " call enter_trap_no_irq \n" \
+ " call " #title "_handler\n" \
+ " jmp common_trap_exit \n");
+
+#define EH_ENTRY_NO_CODE(ec, title) \
+ extern "C" void title##_asm_entry(); \
+ extern "C" void title##_handler(TrapFrame*) __attribute__((used)); \
+ asm( \
+ ".globl " #title "_asm_entry\n" \
+ "" #title "_asm_entry: \n" \
+ " pushl $0x0\n" \
+ " pusha\n" \
+ " pushl %ds\n" \
+ " pushl %es\n" \
+ " pushl %fs\n" \
+ " pushl %gs\n" \
+ " pushl %ss\n" \
+ " mov $" __STRINGIFY(GDT_SELECTOR_DATA0) ", %ax\n" \
+ " mov %ax, %ds\n" \
+ " mov %ax, %es\n" \
+ " mov $" __STRINGIFY(GDT_SELECTOR_PROC) ", %ax\n" \
+ " mov %ax, %fs\n" \
+ " pushl %esp \n" /* set TrapFrame::regs */ \
+ " subl $" __STRINGIFY(TRAP_FRAME_SIZE - 4) ", %esp \n" \
+ " pushl %esp \n" \
+ " cld\n" \
+ " call enter_trap_no_irq \n" \
+ " call " #title "_handler\n" \
+ " jmp common_trap_exit \n");
+
+#elif ARCH(X86_64)
+#define EH_ENTRY(ec, title) \
+ extern "C" void title##_asm_entry(); \
+ extern "C" void title##_handler(TrapFrame*); \
+ asm( \
+ ".globl " #title "_asm_entry\n" \
+ "" #title "_asm_entry: \n" \
+ " cli;hlt;\n" \
+);
+
+#define EH_ENTRY_NO_CODE(ec, title) \
+ extern "C" void title##_handler(TrapFrame*); \
+ extern "C" void title##_asm_entry(); \
+asm( \
+ ".globl " #title "_asm_entry\n" \
+ "" #title "_asm_entry: \n" \
+ " cli;hlt;\n" \
+);
+#endif
+
+// clang-format on
+
+static void dump(const RegisterState& regs)
+{
+ u16 ss;
+ u32 esp;
+
+ if (!(regs.cs & 3)) {
+ ss = regs.ss;
+ esp = regs.esp;
+ } else {
+ ss = regs.userspace_ss;
+ esp = regs.userspace_esp;
+ }
+
+ dbgln("Exception code: {:04x} (isr: {:04x})", regs.exception_code, regs.isr_number);
+ dbgln(" pc={:04x}:{:08x} eflags={:08x}", (u16)regs.cs, regs.eip, regs.eflags);
+ dbgln(" stack={:04x}:{:08x}", ss, esp);
+ dbgln(" ds={:04x} es={:04x} fs={:04x} gs={:04x}", (u16)regs.ds, (u16)regs.es, (u16)regs.fs, (u16)regs.gs);
+ dbgln(" eax={:08x} ebx={:08x} ecx={:08x} edx={:08x}", regs.eax, regs.ebx, regs.ecx, regs.edx);
+ dbgln(" ebp={:08x} esp={:08x} esi={:08x} edi={:08x}", regs.ebp, regs.esp, regs.esi, regs.edi);
+ dbgln(" cr0={:08x} cr2={:08x} cr3={:08x} cr4={:08x}", read_cr0(), read_cr2(), read_cr3(), read_cr4());
+}
+
+void handle_crash(RegisterState& regs, const char* description, int signal, bool out_of_memory)
+{
+ auto process = Process::current();
+ if (!process) {
+ PANIC("{} with !current", description);
+ }
+
+ // If a process crashed while inspecting another process,
+ // make sure we switch back to the right page tables.
+ MM.enter_process_paging_scope(*process);
+
+ dmesgln("CRASH: CPU #{} {} in ring {}", Processor::id(), description, (regs.cs & 3));
+ dump(regs);
+
+ if (!(regs.cs & 3)) {
+ PANIC("Crash in ring 0");
+ }
+
+ process->crash(signal, regs.eip, out_of_memory);
+}
+
+EH_ENTRY_NO_CODE(6, illegal_instruction);
+void illegal_instruction_handler(TrapFrame* trap)
+{
+ clac();
+ handle_crash(*trap->regs, "Illegal instruction", SIGILL);
+}
+
+EH_ENTRY_NO_CODE(0, divide_error);
+void divide_error_handler(TrapFrame* trap)
+{
+ clac();
+ handle_crash(*trap->regs, "Divide error", SIGFPE);
+}
+
+EH_ENTRY(13, general_protection_fault);
+void general_protection_fault_handler(TrapFrame* trap)
+{
+ clac();
+ handle_crash(*trap->regs, "General protection fault", SIGSEGV);
+}
+
+// 7: FPU not available exception
+EH_ENTRY_NO_CODE(7, fpu_exception);
+void fpu_exception_handler(TrapFrame*)
+{
+ // Just clear the TS flag. We've already restored the FPU state eagerly.
+ // FIXME: It would be nice if we didn't have to do this at all.
+ asm volatile("clts");
+}
+
+// 14: Page Fault
+EH_ENTRY(14, page_fault);
+void page_fault_handler(TrapFrame* trap)
+{
+ clac();
+
+ auto& regs = *trap->regs;
+ auto fault_address = read_cr2();
+
+ if constexpr (PAGE_FAULT_DEBUG) {
+ u32 fault_page_directory = read_cr3();
+ dbgln("CPU #{} ring {} {} page fault in PD={:#x}, {}{} {}",
+ Processor::is_initialized() ? Processor::id() : 0,
+ regs.cs & 3,
+ regs.exception_code & 1 ? "PV" : "NP",
+ fault_page_directory,
+ regs.exception_code & 8 ? "reserved-bit " : "",
+ regs.exception_code & 2 ? "write" : "read",
+ VirtualAddress(fault_address));
+
+ dump(regs);
+ }
+
+ bool faulted_in_kernel = !(regs.cs & 3);
+
+ if (faulted_in_kernel && Processor::current().in_irq()) {
+ // If we're faulting in an IRQ handler, first check if we failed
+ // due to safe_memcpy, safe_strnlen, or safe_memset. If we did,
+ // gracefully continue immediately. Because we're in an IRQ handler
+ // we can't really try to resolve the page fault in a meaningful
+ // way, so we need to do this before calling into
+ // MemoryManager::handle_page_fault, which would just bail and
+ // request a crash
+ if (handle_safe_access_fault(regs, fault_address))
+ return;
+ }
+
+ auto current_thread = Thread::current();
+
+ if (current_thread) {
+ current_thread->set_handling_page_fault(true);
+ PerformanceManager::add_page_fault_event(*current_thread, regs);
+ }
+
+ ScopeGuard guard = [current_thread] {
+ if (current_thread)
+ current_thread->set_handling_page_fault(false);
+ };
+
+ if (!faulted_in_kernel && !MM.validate_user_stack(current_thread->process(), VirtualAddress(regs.userspace_esp))) {
+ dbgln("Invalid stack pointer: {}", VirtualAddress(regs.userspace_esp));
+ handle_crash(regs, "Bad stack on page fault", SIGSTKFLT);
+ }
+
+ if (fault_address >= (FlatPtr)&start_of_ro_after_init && fault_address < (FlatPtr)&end_of_ro_after_init) {
+ dump(regs);
+ PANIC("Attempt to write into READONLY_AFTER_INIT section");
+ }
+
+ if (fault_address >= (FlatPtr)&start_of_unmap_after_init && fault_address < (FlatPtr)&end_of_unmap_after_init) {
+ dump(regs);
+ PANIC("Attempt to access UNMAP_AFTER_INIT section");
+ }
+
+ PageFault fault { regs.exception_code, VirtualAddress { fault_address } };
+ auto response = MM.handle_page_fault(fault);
+
+ if (response == PageFaultResponse::ShouldCrash || response == PageFaultResponse::OutOfMemory) {
+ if (faulted_in_kernel && handle_safe_access_fault(regs, fault_address)) {
+ // If this would be a ring0 (kernel) fault and the fault was triggered by
+ // safe_memcpy, safe_strnlen, or safe_memset then we resume execution at
+ // the appropriate _fault label rather than crashing
+ return;
+ }
+
+ if (response != PageFaultResponse::OutOfMemory && current_thread) {
+ if (current_thread->has_signal_handler(SIGSEGV)) {
+ current_thread->send_urgent_signal_to_self(SIGSEGV);
+ return;
+ }
+ }
+
+ dbgln("Unrecoverable page fault, {}{}{} address {}",
+ regs.exception_code & PageFaultFlags::ReservedBitViolation ? "reserved bit violation / " : "",
+ regs.exception_code & PageFaultFlags::InstructionFetch ? "instruction fetch / " : "",
+ regs.exception_code & PageFaultFlags::Write ? "write to" : "read from",
+ VirtualAddress(fault_address));
+ u32 malloc_scrub_pattern = explode_byte(MALLOC_SCRUB_BYTE);
+ u32 free_scrub_pattern = explode_byte(FREE_SCRUB_BYTE);
+ u32 kmalloc_scrub_pattern = explode_byte(KMALLOC_SCRUB_BYTE);
+ u32 kfree_scrub_pattern = explode_byte(KFREE_SCRUB_BYTE);
+ u32 slab_alloc_scrub_pattern = explode_byte(SLAB_ALLOC_SCRUB_BYTE);
+ u32 slab_dealloc_scrub_pattern = explode_byte(SLAB_DEALLOC_SCRUB_BYTE);
+ if ((fault_address & 0xffff0000) == (malloc_scrub_pattern & 0xffff0000)) {
+ dbgln("Note: Address {} looks like it may be uninitialized malloc() memory", VirtualAddress(fault_address));
+ } else if ((fault_address & 0xffff0000) == (free_scrub_pattern & 0xffff0000)) {
+ dbgln("Note: Address {} looks like it may be recently free()'d memory", VirtualAddress(fault_address));
+ } else if ((fault_address & 0xffff0000) == (kmalloc_scrub_pattern & 0xffff0000)) {
+ dbgln("Note: Address {} looks like it may be uninitialized kmalloc() memory", VirtualAddress(fault_address));
+ } else if ((fault_address & 0xffff0000) == (kfree_scrub_pattern & 0xffff0000)) {
+ dbgln("Note: Address {} looks like it may be recently kfree()'d memory", VirtualAddress(fault_address));
+ } else if ((fault_address & 0xffff0000) == (slab_alloc_scrub_pattern & 0xffff0000)) {
+ dbgln("Note: Address {} looks like it may be uninitialized slab_alloc() memory", VirtualAddress(fault_address));
+ } else if ((fault_address & 0xffff0000) == (slab_dealloc_scrub_pattern & 0xffff0000)) {
+ dbgln("Note: Address {} looks like it may be recently slab_dealloc()'d memory", VirtualAddress(fault_address));
+ } else if (fault_address < 4096) {
+ dbgln("Note: Address {} looks like a possible nullptr dereference", VirtualAddress(fault_address));
+ }
+
+ if (current_thread) {
+ auto& current_process = current_thread->process();
+ if (current_process.is_user_process()) {
+ current_process.set_coredump_metadata("fault_address", String::formatted("{:p}", fault_address));
+ current_process.set_coredump_metadata("fault_type", fault.type() == PageFault::Type::PageNotPresent ? "NotPresent" : "ProtectionViolation");
+ String fault_access;
+ if (fault.is_instruction_fetch())
+ fault_access = "Execute";
+ else
+ fault_access = fault.access() == PageFault::Access::Read ? "Read" : "Write";
+ current_process.set_coredump_metadata("fault_access", fault_access);
+ }
+ }
+
+ handle_crash(regs, "Page Fault", SIGSEGV, response == PageFaultResponse::OutOfMemory);
+ } else if (response == PageFaultResponse::Continue) {
+ dbgln_if(PAGE_FAULT_DEBUG, "Continuing after resolved page fault");
+ } else {
+ VERIFY_NOT_REACHED();
+ }
+}
+
+EH_ENTRY_NO_CODE(1, debug);
+void debug_handler(TrapFrame* trap)
+{
+ clac();
+ auto& regs = *trap->regs;
+ auto current_thread = Thread::current();
+ auto& process = current_thread->process();
+ if ((regs.cs & 3) == 0) {
+ PANIC("Debug exception in ring 0");
+ }
+ constexpr u8 REASON_SINGLESTEP = 14;
+ auto debug_status = read_dr6();
+ auto should_trap_mask = (1 << REASON_SINGLESTEP) | 0b1111;
+ if ((debug_status & should_trap_mask) == 0)
+ return;
+ if (auto tracer = process.tracer()) {
+ tracer->set_regs(regs);
+ }
+ current_thread->send_urgent_signal_to_self(SIGTRAP);
+ write_dr6(debug_status & ~(should_trap_mask));
+}
+
+EH_ENTRY_NO_CODE(3, breakpoint);
+void breakpoint_handler(TrapFrame* trap)
+{
+ clac();
+ auto& regs = *trap->regs;
+ auto current_thread = Thread::current();
+ auto& process = current_thread->process();
+ if ((regs.cs & 3) == 0) {
+ PANIC("Breakpoint trap in ring 0");
+ }
+ if (auto tracer = process.tracer()) {
+ tracer->set_regs(regs);
+ }
+ current_thread->send_urgent_signal_to_self(SIGTRAP);
+}
+
+#define EH(i, msg) \
+ static void _exception##i() \
+ { \
+ dbgln("{}", msg); \
+ PANIC("cr0={:08x} cr2={:08x} cr3={:08x} cr4={:08x}", read_cr0(), read_cr2(), read_cr3(), read_cr4()); \
+ }
+
+EH(2, "Unknown error")
+EH(4, "Overflow")
+EH(5, "Bounds check")
+EH(8, "Double fault")
+EH(9, "Coprocessor segment overrun")
+EH(10, "Invalid TSS")
+EH(11, "Segment not present")
+EH(12, "Stack exception")
+EH(15, "Unknown error")
+EH(16, "Coprocessor error")
+
+extern "C" void pre_init_finished(void) __attribute__((used));
+extern "C" void post_init_finished(void) __attribute__((used));
+extern "C" void handle_interrupt(TrapFrame*) __attribute__((used));
+
+extern "C" UNMAP_AFTER_INIT void pre_init_finished(void)
+{
+ VERIFY(g_scheduler_lock.own_lock());
+
+ // Because init_finished() will wait on the other APs, we need
+ // to release the scheduler lock so that the other APs can also get
+ // to this point
+
+ // The target flags will get restored upon leaving the trap
+ u32 prev_flags = cpu_flags();
+ Scheduler::leave_on_first_switch(prev_flags);
+}
+
+extern "C" UNMAP_AFTER_INIT void post_init_finished(void)
+{
+ // We need to re-acquire the scheduler lock before a context switch
+ // transfers control into the idle loop, which needs the lock held
+ Scheduler::prepare_for_idle_loop();
+}
+
+void handle_interrupt(TrapFrame* trap)
+{
+ clac();
+ auto& regs = *trap->regs;
+ VERIFY(regs.isr_number >= IRQ_VECTOR_BASE && regs.isr_number <= (IRQ_VECTOR_BASE + GENERIC_INTERRUPT_HANDLERS_COUNT));
+ u8 irq = (u8)(regs.isr_number - 0x50);
+ s_entropy_source_interrupts.add_random_event(irq);
+ auto* handler = s_interrupt_handler[irq];
+ VERIFY(handler);
+ handler->increment_invoking_counter();
+ handler->handle_interrupt(regs);
+ handler->eoi();
+}
+
+const DescriptorTablePointer& get_idtr()
+{
+ return s_idtr;
+}
+
+static void unimp_trap()
+{
+ PANIC("Unhandled IRQ");
+}
+
+GenericInterruptHandler& get_interrupt_handler(u8 interrupt_number)
+{
+ auto*& handler_slot = s_interrupt_handler[interrupt_number];
+ VERIFY(handler_slot != nullptr);
+ return *handler_slot;
+}
+
+static void revert_to_unused_handler(u8 interrupt_number)
+{
+ auto handler = new UnhandledInterruptHandler(interrupt_number);
+ handler->register_interrupt_handler();
+}
+
+void register_generic_interrupt_handler(u8 interrupt_number, GenericInterruptHandler& handler)
+{
+ VERIFY(interrupt_number < GENERIC_INTERRUPT_HANDLERS_COUNT);
+ auto*& handler_slot = s_interrupt_handler[interrupt_number];
+ if (handler_slot != nullptr) {
+ if (handler_slot->type() == HandlerType::UnhandledInterruptHandler) {
+ if (handler_slot) {
+ auto* unhandled_handler = static_cast<UnhandledInterruptHandler*>(handler_slot);
+ unhandled_handler->unregister_interrupt_handler();
+ delete unhandled_handler;
+ }
+ handler_slot = &handler;
+ return;
+ }
+ if (handler_slot->is_shared_handler() && !handler_slot->is_sharing_with_others()) {
+ VERIFY(handler_slot->type() == HandlerType::SharedIRQHandler);
+ static_cast<SharedIRQHandler*>(handler_slot)->register_handler(handler);
+ return;
+ }
+ if (!handler_slot->is_shared_handler()) {
+ if (handler_slot->type() == HandlerType::SpuriousInterruptHandler) {
+ static_cast<SpuriousInterruptHandler*>(handler_slot)->register_handler(handler);
+ return;
+ }
+ VERIFY(handler_slot->type() == HandlerType::IRQHandler);
+ auto& previous_handler = *handler_slot;
+ handler_slot = nullptr;
+ SharedIRQHandler::initialize(interrupt_number);
+ VERIFY(handler_slot);
+ static_cast<SharedIRQHandler*>(handler_slot)->register_handler(previous_handler);
+ static_cast<SharedIRQHandler*>(handler_slot)->register_handler(handler);
+ return;
+ }
+ VERIFY_NOT_REACHED();
+ } else {
+ handler_slot = &handler;
+ }
+}
+
+void unregister_generic_interrupt_handler(u8 interrupt_number, GenericInterruptHandler& handler)
+{
+ auto*& handler_slot = s_interrupt_handler[interrupt_number];
+ VERIFY(handler_slot != nullptr);
+ if (handler_slot->type() == HandlerType::UnhandledInterruptHandler) {
+ dbgln("Trying to unregister unused handler (?)");
+ return;
+ }
+ if (handler_slot->is_shared_handler() && !handler_slot->is_sharing_with_others()) {
+ VERIFY(handler_slot->type() == HandlerType::SharedIRQHandler);
+ auto* shared_handler = static_cast<SharedIRQHandler*>(handler_slot);
+ shared_handler->unregister_handler(handler);
+ if (!shared_handler->sharing_devices_count()) {
+ handler_slot = nullptr;
+ revert_to_unused_handler(interrupt_number);
+ }
+ return;
+ }
+ if (!handler_slot->is_shared_handler()) {
+ VERIFY(handler_slot->type() == HandlerType::IRQHandler);
+ handler_slot = nullptr;
+ revert_to_unused_handler(interrupt_number);
+ return;
+ }
+ VERIFY_NOT_REACHED();
+}
+
+UNMAP_AFTER_INIT void register_interrupt_handler(u8 index, void (*handler)())
+{
+ // FIXME: Why is that with selector 8?
+ // FIXME: Is the Gate Type really required to be an Interrupt
+ // FIXME: What's up with that storage segment 0?
+ s_idt[index] = IDTEntry((FlatPtr)handler, 8, IDTEntryType::InterruptGate32, 0, 0);
+}
+
+UNMAP_AFTER_INIT void register_user_callable_interrupt_handler(u8 index, void (*handler)())
+{
+ // FIXME: Why is that with selector 8?
+ // FIXME: Is the Gate Type really required to be a Trap
+ // FIXME: What's up with that storage segment 0?
+ s_idt[index] = IDTEntry((FlatPtr)handler, 8, IDTEntryType::TrapGate32, 0, 3);
+}
+
+UNMAP_AFTER_INIT void flush_idt()
+{
+ asm("lidt %0" ::"m"(s_idtr));
+}
+
+UNMAP_AFTER_INIT void idt_init()
+{
+ s_idtr.address = s_idt;
+ s_idtr.limit = 256 * 8 - 1;
+
+ register_interrupt_handler(0x00, divide_error_asm_entry);
+ register_user_callable_interrupt_handler(0x01, debug_asm_entry);
+ register_interrupt_handler(0x02, _exception2);
+ register_user_callable_interrupt_handler(0x03, breakpoint_asm_entry);
+ register_interrupt_handler(0x04, _exception4);
+ register_interrupt_handler(0x05, _exception5);
+ register_interrupt_handler(0x06, illegal_instruction_asm_entry);
+ register_interrupt_handler(0x07, fpu_exception_asm_entry);
+ register_interrupt_handler(0x08, _exception8);
+ register_interrupt_handler(0x09, _exception9);
+ register_interrupt_handler(0x0a, _exception10);
+ register_interrupt_handler(0x0b, _exception11);
+ register_interrupt_handler(0x0c, _exception12);
+ register_interrupt_handler(0x0d, general_protection_fault_asm_entry);
+ register_interrupt_handler(0x0e, page_fault_asm_entry);
+ register_interrupt_handler(0x0f, _exception15);
+ register_interrupt_handler(0x10, _exception16);
+
+ for (u8 i = 0x11; i < 0x50; i++)
+ register_interrupt_handler(i, unimp_trap);
+
+ dbgln("Initializing unhandled interrupt handlers");
+ register_interrupt_handler(0x50, interrupt_80_asm_entry);
+ register_interrupt_handler(0x51, interrupt_81_asm_entry);
+ register_interrupt_handler(0x52, interrupt_82_asm_entry);
+ register_interrupt_handler(0x53, interrupt_83_asm_entry);
+ register_interrupt_handler(0x54, interrupt_84_asm_entry);
+ register_interrupt_handler(0x55, interrupt_85_asm_entry);
+ register_interrupt_handler(0x56, interrupt_86_asm_entry);
+ register_interrupt_handler(0x57, interrupt_87_asm_entry);
+ register_interrupt_handler(0x58, interrupt_88_asm_entry);
+ register_interrupt_handler(0x59, interrupt_89_asm_entry);
+ register_interrupt_handler(0x5a, interrupt_90_asm_entry);
+ register_interrupt_handler(0x5b, interrupt_91_asm_entry);
+ register_interrupt_handler(0x5c, interrupt_92_asm_entry);
+ register_interrupt_handler(0x5d, interrupt_93_asm_entry);
+ register_interrupt_handler(0x5e, interrupt_94_asm_entry);
+ register_interrupt_handler(0x5f, interrupt_95_asm_entry);
+ register_interrupt_handler(0x60, interrupt_96_asm_entry);
+ register_interrupt_handler(0x61, interrupt_97_asm_entry);
+ register_interrupt_handler(0x62, interrupt_98_asm_entry);
+ register_interrupt_handler(0x63, interrupt_99_asm_entry);
+ register_interrupt_handler(0x64, interrupt_100_asm_entry);
+ register_interrupt_handler(0x65, interrupt_101_asm_entry);
+ register_interrupt_handler(0x66, interrupt_102_asm_entry);
+ register_interrupt_handler(0x67, interrupt_103_asm_entry);
+ register_interrupt_handler(0x68, interrupt_104_asm_entry);
+ register_interrupt_handler(0x69, interrupt_105_asm_entry);
+ register_interrupt_handler(0x6a, interrupt_106_asm_entry);
+ register_interrupt_handler(0x6b, interrupt_107_asm_entry);
+ register_interrupt_handler(0x6c, interrupt_108_asm_entry);
+ register_interrupt_handler(0x6d, interrupt_109_asm_entry);
+ register_interrupt_handler(0x6e, interrupt_110_asm_entry);
+ register_interrupt_handler(0x6f, interrupt_111_asm_entry);
+ register_interrupt_handler(0x70, interrupt_112_asm_entry);
+ register_interrupt_handler(0x71, interrupt_113_asm_entry);
+ register_interrupt_handler(0x72, interrupt_114_asm_entry);
+ register_interrupt_handler(0x73, interrupt_115_asm_entry);
+ register_interrupt_handler(0x74, interrupt_116_asm_entry);
+ register_interrupt_handler(0x75, interrupt_117_asm_entry);
+ register_interrupt_handler(0x76, interrupt_118_asm_entry);
+ register_interrupt_handler(0x77, interrupt_119_asm_entry);
+ register_interrupt_handler(0x78, interrupt_120_asm_entry);
+ register_interrupt_handler(0x79, interrupt_121_asm_entry);
+ register_interrupt_handler(0x7a, interrupt_122_asm_entry);
+ register_interrupt_handler(0x7b, interrupt_123_asm_entry);
+ register_interrupt_handler(0x7c, interrupt_124_asm_entry);
+ register_interrupt_handler(0x7d, interrupt_125_asm_entry);
+ register_interrupt_handler(0x7e, interrupt_126_asm_entry);
+ register_interrupt_handler(0x7f, interrupt_127_asm_entry);
+ register_interrupt_handler(0x80, interrupt_128_asm_entry);
+ register_interrupt_handler(0x81, interrupt_129_asm_entry);
+ register_interrupt_handler(0x82, interrupt_130_asm_entry);
+ register_interrupt_handler(0x83, interrupt_131_asm_entry);
+ register_interrupt_handler(0x84, interrupt_132_asm_entry);
+ register_interrupt_handler(0x85, interrupt_133_asm_entry);
+ register_interrupt_handler(0x86, interrupt_134_asm_entry);
+ register_interrupt_handler(0x87, interrupt_135_asm_entry);
+ register_interrupt_handler(0x88, interrupt_136_asm_entry);
+ register_interrupt_handler(0x89, interrupt_137_asm_entry);
+ register_interrupt_handler(0x8a, interrupt_138_asm_entry);
+ register_interrupt_handler(0x8b, interrupt_139_asm_entry);
+ register_interrupt_handler(0x8c, interrupt_140_asm_entry);
+ register_interrupt_handler(0x8d, interrupt_141_asm_entry);
+ register_interrupt_handler(0x8e, interrupt_142_asm_entry);
+ register_interrupt_handler(0x8f, interrupt_143_asm_entry);
+ register_interrupt_handler(0x90, interrupt_144_asm_entry);
+ register_interrupt_handler(0x91, interrupt_145_asm_entry);
+ register_interrupt_handler(0x92, interrupt_146_asm_entry);
+ register_interrupt_handler(0x93, interrupt_147_asm_entry);
+ register_interrupt_handler(0x94, interrupt_148_asm_entry);
+ register_interrupt_handler(0x95, interrupt_149_asm_entry);
+ register_interrupt_handler(0x96, interrupt_150_asm_entry);
+ register_interrupt_handler(0x97, interrupt_151_asm_entry);
+ register_interrupt_handler(0x98, interrupt_152_asm_entry);
+ register_interrupt_handler(0x99, interrupt_153_asm_entry);
+ register_interrupt_handler(0x9a, interrupt_154_asm_entry);
+ register_interrupt_handler(0x9b, interrupt_155_asm_entry);
+ register_interrupt_handler(0x9c, interrupt_156_asm_entry);
+ register_interrupt_handler(0x9d, interrupt_157_asm_entry);
+ register_interrupt_handler(0x9e, interrupt_158_asm_entry);
+ register_interrupt_handler(0x9f, interrupt_159_asm_entry);
+ register_interrupt_handler(0xa0, interrupt_160_asm_entry);
+ register_interrupt_handler(0xa1, interrupt_161_asm_entry);
+ register_interrupt_handler(0xa2, interrupt_162_asm_entry);
+ register_interrupt_handler(0xa3, interrupt_163_asm_entry);
+ register_interrupt_handler(0xa4, interrupt_164_asm_entry);
+ register_interrupt_handler(0xa5, interrupt_165_asm_entry);
+ register_interrupt_handler(0xa6, interrupt_166_asm_entry);
+ register_interrupt_handler(0xa7, interrupt_167_asm_entry);
+ register_interrupt_handler(0xa8, interrupt_168_asm_entry);
+ register_interrupt_handler(0xa9, interrupt_169_asm_entry);
+ register_interrupt_handler(0xaa, interrupt_170_asm_entry);
+ register_interrupt_handler(0xab, interrupt_171_asm_entry);
+ register_interrupt_handler(0xac, interrupt_172_asm_entry);
+ register_interrupt_handler(0xad, interrupt_173_asm_entry);
+ register_interrupt_handler(0xae, interrupt_174_asm_entry);
+ register_interrupt_handler(0xaf, interrupt_175_asm_entry);
+ register_interrupt_handler(0xb0, interrupt_176_asm_entry);
+ register_interrupt_handler(0xb1, interrupt_177_asm_entry);
+ register_interrupt_handler(0xb2, interrupt_178_asm_entry);
+ register_interrupt_handler(0xb3, interrupt_179_asm_entry);
+ register_interrupt_handler(0xb4, interrupt_180_asm_entry);
+ register_interrupt_handler(0xb5, interrupt_181_asm_entry);
+ register_interrupt_handler(0xb6, interrupt_182_asm_entry);
+ register_interrupt_handler(0xb7, interrupt_183_asm_entry);
+ register_interrupt_handler(0xb8, interrupt_184_asm_entry);
+ register_interrupt_handler(0xb9, interrupt_185_asm_entry);
+ register_interrupt_handler(0xba, interrupt_186_asm_entry);
+ register_interrupt_handler(0xbb, interrupt_187_asm_entry);
+ register_interrupt_handler(0xbc, interrupt_188_asm_entry);
+ register_interrupt_handler(0xbd, interrupt_189_asm_entry);
+ register_interrupt_handler(0xbe, interrupt_190_asm_entry);
+ register_interrupt_handler(0xbf, interrupt_191_asm_entry);
+ register_interrupt_handler(0xc0, interrupt_192_asm_entry);
+ register_interrupt_handler(0xc1, interrupt_193_asm_entry);
+ register_interrupt_handler(0xc2, interrupt_194_asm_entry);
+ register_interrupt_handler(0xc3, interrupt_195_asm_entry);
+ register_interrupt_handler(0xc4, interrupt_196_asm_entry);
+ register_interrupt_handler(0xc5, interrupt_197_asm_entry);
+ register_interrupt_handler(0xc6, interrupt_198_asm_entry);
+ register_interrupt_handler(0xc7, interrupt_199_asm_entry);
+ register_interrupt_handler(0xc8, interrupt_200_asm_entry);
+ register_interrupt_handler(0xc9, interrupt_201_asm_entry);
+ register_interrupt_handler(0xca, interrupt_202_asm_entry);
+ register_interrupt_handler(0xcb, interrupt_203_asm_entry);
+ register_interrupt_handler(0xcc, interrupt_204_asm_entry);
+ register_interrupt_handler(0xcd, interrupt_205_asm_entry);
+ register_interrupt_handler(0xce, interrupt_206_asm_entry);
+ register_interrupt_handler(0xcf, interrupt_207_asm_entry);
+ register_interrupt_handler(0xd0, interrupt_208_asm_entry);
+ register_interrupt_handler(0xd1, interrupt_209_asm_entry);
+ register_interrupt_handler(0xd2, interrupt_210_asm_entry);
+ register_interrupt_handler(0xd3, interrupt_211_asm_entry);
+ register_interrupt_handler(0xd4, interrupt_212_asm_entry);
+ register_interrupt_handler(0xd5, interrupt_213_asm_entry);
+ register_interrupt_handler(0xd6, interrupt_214_asm_entry);
+ register_interrupt_handler(0xd7, interrupt_215_asm_entry);
+ register_interrupt_handler(0xd8, interrupt_216_asm_entry);
+ register_interrupt_handler(0xd9, interrupt_217_asm_entry);
+ register_interrupt_handler(0xda, interrupt_218_asm_entry);
+ register_interrupt_handler(0xdb, interrupt_219_asm_entry);
+ register_interrupt_handler(0xdc, interrupt_220_asm_entry);
+ register_interrupt_handler(0xdd, interrupt_221_asm_entry);
+ register_interrupt_handler(0xde, interrupt_222_asm_entry);
+ register_interrupt_handler(0xdf, interrupt_223_asm_entry);
+ register_interrupt_handler(0xe0, interrupt_224_asm_entry);
+ register_interrupt_handler(0xe1, interrupt_225_asm_entry);
+ register_interrupt_handler(0xe2, interrupt_226_asm_entry);
+ register_interrupt_handler(0xe3, interrupt_227_asm_entry);
+ register_interrupt_handler(0xe4, interrupt_228_asm_entry);
+ register_interrupt_handler(0xe5, interrupt_229_asm_entry);
+ register_interrupt_handler(0xe6, interrupt_230_asm_entry);
+ register_interrupt_handler(0xe7, interrupt_231_asm_entry);
+ register_interrupt_handler(0xe8, interrupt_232_asm_entry);
+ register_interrupt_handler(0xe9, interrupt_233_asm_entry);
+ register_interrupt_handler(0xea, interrupt_234_asm_entry);
+ register_interrupt_handler(0xeb, interrupt_235_asm_entry);
+ register_interrupt_handler(0xec, interrupt_236_asm_entry);
+ register_interrupt_handler(0xed, interrupt_237_asm_entry);
+ register_interrupt_handler(0xee, interrupt_238_asm_entry);
+ register_interrupt_handler(0xef, interrupt_239_asm_entry);
+ register_interrupt_handler(0xf0, interrupt_240_asm_entry);
+ register_interrupt_handler(0xf1, interrupt_241_asm_entry);
+ register_interrupt_handler(0xf2, interrupt_242_asm_entry);
+ register_interrupt_handler(0xf3, interrupt_243_asm_entry);
+ register_interrupt_handler(0xf4, interrupt_244_asm_entry);
+ register_interrupt_handler(0xf5, interrupt_245_asm_entry);
+ register_interrupt_handler(0xf6, interrupt_246_asm_entry);
+ register_interrupt_handler(0xf7, interrupt_247_asm_entry);
+ register_interrupt_handler(0xf8, interrupt_248_asm_entry);
+ register_interrupt_handler(0xf9, interrupt_249_asm_entry);
+ register_interrupt_handler(0xfa, interrupt_250_asm_entry);
+ register_interrupt_handler(0xfb, interrupt_251_asm_entry);
+ register_interrupt_handler(0xfc, interrupt_252_asm_entry);
+ register_interrupt_handler(0xfd, interrupt_253_asm_entry);
+ register_interrupt_handler(0xfe, interrupt_254_asm_entry);
+ register_interrupt_handler(0xff, interrupt_255_asm_entry);
+
+ for (u8 i = 0; i < GENERIC_INTERRUPT_HANDLERS_COUNT; ++i) {
+ auto* handler = new UnhandledInterruptHandler(i);
+ handler->register_interrupt_handler();
+ }
+
+ flush_idt();
+}
+
+}