Provide stubbed handlers for many more x86 exceptions

I am now officially a big-boy OS developer, I read the Intel manuals for this!! (Not that the OSDev wiki doesn't have the information, but it was missing descriptions for some more obscure exceptions)
This commit is contained in:
apio 2022-11-18 20:51:25 +01:00
parent 860f13cd7e
commit 109de54822
3 changed files with 121 additions and 16 deletions

View File

@ -1,8 +1,3 @@
section .data
global __divisor
__divisor:
dd 0
section .text section .text
global enable_sse global enable_sse
enable_sse: enable_sse:
@ -77,6 +72,8 @@ load_tr:
%endmacro %endmacro
extern arch_interrupt_entry extern arch_interrupt_entry
extern arch_double_fault
extern arch_machine_check
_asm_interrupt_entry: _asm_interrupt_entry:
push rax push rax
@ -120,4 +117,36 @@ _asm_interrupt_entry:
iretq iretq
ISR 0 ; divide by zero ISR 0 ; divide by zero (#DE)
ISR 1 ; debug (#DB)
ISR 2 ; non-maskable interrupt
ISR 3 ; breakpoint (#BP)
ISR 4 ; overflow (#OF)
ISR 5 ; bound range exceeded (#BR)
ISR 6 ; invalid opcode (#UD)
ISR 7 ; device not available (#NM)
global _isr8
_isr8: ; double fault (#DF)
jmp arch_double_fault
ud2 ; we aren't even pushing a return address for arch_double_fault, this is truly UNREACHABLE
; ISR 9 obsolete
ISR_ERROR 10 ; invalid tss (#TS)
ISR_ERROR 11 ; segment not present (#NP)
ISR_ERROR 12 ; stack-segment fault (#SS)
ISR_ERROR 13 ; general protection fault (#GP)
ISR_ERROR 14 ; page fault (#PF)
; ISR 15 reserved
ISR 16 ; x87 floating-point exception (#MF)
ISR_ERROR 17 ; alignment check (#AC)
global _isr18
_isr18: ; machine check (#MC)
jmp arch_machine_check
ud2 ; same as above
ISR 19 ; SIMD floating-point exception (#XM)
ISR 20 ; virtualization exception (#VE)
ISR_ERROR 21 ; control-protection exception (#CP)
; ISR 22-31 reserved

View File

@ -162,10 +162,50 @@ static void idt_add_handler(short num, void* handler, u8 type_attr)
#define TRAP(x) idt_add_handler(x, (void*)_isr##x, IDT_TA_TrapGate) #define TRAP(x) idt_add_handler(x, (void*)_isr##x, IDT_TA_TrapGate)
INT(0); INT(0);
INT(1);
INT(2);
INT(3);
INT(4);
INT(5);
INT(6);
INT(7);
INT(8);
INT(10);
INT(11);
INT(12);
INT(13);
INT(14);
INT(16);
INT(17);
INT(18);
INT(19);
INT(20);
INT(21);
static void setup_idt() static void setup_idt()
{ {
TRAP(0); // divide by zero memset(idt, 0, sizeof(idt));
TRAP(0);
TRAP(1);
TRAP(2);
TRAP(3);
TRAP(4);
TRAP(5);
TRAP(6);
TRAP(7);
TRAP(8);
TRAP(10);
TRAP(11);
TRAP(12);
TRAP(13);
TRAP(14);
TRAP(16);
TRAP(17);
TRAP(18);
TRAP(19);
TRAP(20);
TRAP(21);
static IDTR idtr; static IDTR idtr;
idtr.limit = 0x0FFF; idtr.limit = 0x0FFF;
@ -175,14 +215,40 @@ static void setup_idt()
// Interrupt handling // Interrupt handling
#define FIXME_UNHANDLED_INTERRUPT(name) \
Serial::println("FIXME(interrupt): " name); \
CPU::efficient_halt();
extern "C" void handle_x86_exception([[maybe_unused]] Registers* regs)
{
switch (regs->isr)
{
case 0: FIXME_UNHANDLED_INTERRUPT("Division by zero");
case 1: FIXME_UNHANDLED_INTERRUPT("Debug interrupt");
case 2: FIXME_UNHANDLED_INTERRUPT("NMI (Non-maskable interrupt)");
case 3: FIXME_UNHANDLED_INTERRUPT("Breakpoint");
case 4: FIXME_UNHANDLED_INTERRUPT("Overflow");
case 5: FIXME_UNHANDLED_INTERRUPT("Bound range exceeded");
case 6: FIXME_UNHANDLED_INTERRUPT("Invalid opcode");
case 7: FIXME_UNHANDLED_INTERRUPT("Device not available");
case 10: FIXME_UNHANDLED_INTERRUPT("Invalid TSS");
case 11: FIXME_UNHANDLED_INTERRUPT("Segment not present");
case 12: FIXME_UNHANDLED_INTERRUPT("Stack-segment fault");
case 13: FIXME_UNHANDLED_INTERRUPT("General protection fault");
case 14: FIXME_UNHANDLED_INTERRUPT("Page fault");
case 16: FIXME_UNHANDLED_INTERRUPT("x87 floating-point exception");
case 17: FIXME_UNHANDLED_INTERRUPT("Alignment check");
case 19: FIXME_UNHANDLED_INTERRUPT("SIMD floating-point exception");
case 20: FIXME_UNHANDLED_INTERRUPT("Virtualization exception");
case 21: FIXME_UNHANDLED_INTERRUPT("Control-protection exception");
default: FIXME_UNHANDLED_INTERRUPT("Reserved exception or #DF/#MC, which shouldn't call handle_x86_exception");
}
}
// Called from _asm_interrupt_entry // Called from _asm_interrupt_entry
extern "C" void arch_interrupt_entry(Registers* regs) extern "C" void arch_interrupt_entry(Registers* regs)
{ {
if (regs->isr < 32) if (regs->isr < 32) handle_x86_exception(regs);
{
Serial::println("Exception catched! Halting.");
CPU::efficient_halt();
}
else else
{ {
Serial::println("IRQ catched! Halting."); Serial::println("IRQ catched! Halting.");
@ -190,6 +256,18 @@ extern "C" void arch_interrupt_entry(Registers* regs)
} }
} }
extern "C" [[noreturn]] void arch_double_fault()
{
Serial::println("ERROR: Catched double fault");
CPU::efficient_halt();
}
extern "C" [[noreturn]] void arch_machine_check()
{
Serial::println("ERROR: Machine check failed");
CPU::efficient_halt();
}
// Generic CPU code // Generic CPU code
static bool test_nx() static bool test_nx()

View File

@ -84,11 +84,9 @@ extern "C" [[noreturn]] void _start()
Serial::println("Successfully unmapped address"); Serial::println("Successfully unmapped address");
extern int __divisor; // divisor is defined as 0, we do it this way so the compiler doesn't catch it (this is *ptr = 16;
// testing exception handling)
[[maybe_unused]] volatile int div_rc = 4 / __divisor;
Serial::println("ERROR: Still here after division by zero"); Serial::println("ERROR: Still here after page fault");
CPU::efficient_halt(); CPU::efficient_halt();
} }