diff options
Diffstat (limited to 'Kernel/Arch/x86/common/Interrupts.cpp')
-rw-r--r-- | Kernel/Arch/x86/common/Interrupts.cpp | 737 |
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(); +} + +} |