From 2f3b34475b5e678d501113cba07af0908e471bab Mon Sep 17 00:00:00 2001 From: Robbe Van Herck Date: Thu, 9 Jan 2020 16:27:19 +0100 Subject: [PATCH] Add Exception handling --- README.md | 2 +- kernel/exception.c | 71 +++++++++++++++++++++++++++++++++++++++++ kernel/exception_list.c | 34 ++++++++++++++++++++ kernel/interrupts.c | 57 +++++++++++++++++++++------------ kernel/terminal.c | 12 ++++--- 5 files changed, 151 insertions(+), 25 deletions(-) create mode 100644 kernel/exception.c create mode 100644 kernel/exception_list.c diff --git a/README.md b/README.md index 8999104..acd52fa 100644 --- a/README.md +++ b/README.md @@ -29,11 +29,11 @@ The kernel is based on [the bare bones kernel from the OSDev wiki](https://wiki. - [x] _Very_ basic memory management - [x] Interrupt handling - [x] Keyboard input +- [x] Exception handling - [ ] Filesystem interaction - [ ] Show files in directory - [ ] Read files in directory - [ ] Write files in directory -- [ ] Exception handling - [ ] Tests - [ ] Running executables from filesystem - [ ] Better memory management diff --git a/kernel/exception.c b/kernel/exception.c new file mode 100644 index 0000000..09ad323 --- /dev/null +++ b/kernel/exception.c @@ -0,0 +1,71 @@ +#ifndef EXCEPTION_C +#define EXCEPTION_C + +#include "terminal.c" + +typedef struct interrupt_frame_struct { + uint32_t eip; + uint32_t cs; + uint32_t eflags; +} interrupt_frame; + +#define EXCEPTION_HANDLER_NO_ERR(NAME, STR) \ +__attribute__((interrupt)) void NAME (interrupt_frame* frame) { \ + outb(0x20, 0x20); \ + bsod(frame, STR, -1); \ +} + +#define EXCEPTION_HANDLER_ERR(NAME, STR) \ +__attribute__((interrupt)) void NAME (interrupt_frame* frame, uint32_t err_code) { \ + outb(0x20, 0x20); \ + bsod(frame, STR, err_code); \ +} + +void bsod(interrupt_frame* frame, char* err_msg, int32_t err_code) { + + terminal_initialize(); + terminal_writestring("An exception occured: "); + terminal_writestring(err_msg); + if(err_code != -1) { + terminal_writestring(" (error code = 0x"); + terminal_writeint(err_code, 16); + terminal_writestring(")"); + } + terminal_writestring("\nHere's what we know:\n"); + terminal_writestring("eip = 0x"); + terminal_writeint(frame->eip, 16); + terminal_writestring("\ncs = 0x"); + terminal_writeint(frame->cs, 16); + terminal_writestring("\neflags = 0b"); + terminal_writeint(frame->eflags, 2); + + + for(;;) { + asm("hlt"); + } +} + +EXCEPTION_HANDLER_NO_ERR(divide_by_zero_handler, "Divide by zero") +EXCEPTION_HANDLER_NO_ERR(debug_handler, "debug") +EXCEPTION_HANDLER_NO_ERR(non_maskable_interrupt_handler, "Non maskable interrupt") +EXCEPTION_HANDLER_NO_ERR(breakpoint_handler, "Breakpoint") +EXCEPTION_HANDLER_NO_ERR(overflow_handler, "Overflow") +EXCEPTION_HANDLER_NO_ERR(bound_range_exceeded_handler, "Bound range exceeded") +EXCEPTION_HANDLER_NO_ERR(invalid_opcode_handler, "Invalid opcode") +EXCEPTION_HANDLER_NO_ERR(device_not_available_handler, "Device not available") +EXCEPTION_HANDLER_ERR(double_fault_handler, "Double fault") +EXCEPTION_HANDLER_NO_ERR(coprocessor_seg_overrun_handler, "Coprocessor seg overrun") +EXCEPTION_HANDLER_ERR(invalid_tss_handler, "Invalid tss") +EXCEPTION_HANDLER_ERR(segment_not_present_handler, "Segment not present") +EXCEPTION_HANDLER_ERR(stack_segment_fault_handler, "Stack segment fault") +EXCEPTION_HANDLER_ERR(general_protection_fault_handler, "General protection fault") +EXCEPTION_HANDLER_ERR(page_fault_handler, "Page fault") +EXCEPTION_HANDLER_NO_ERR(reserved_handler, "Reserved") +EXCEPTION_HANDLER_NO_ERR(x87_fp_exception_handler, "x87 floating point exception") +EXCEPTION_HANDLER_NO_ERR(alignment_check_handler, "Alignment check"); +EXCEPTION_HANDLER_NO_ERR(machine_check_handler, "Machine check"); +EXCEPTION_HANDLER_NO_ERR(simd_fp_exception_handler, "SIMD floating point exception"); +EXCEPTION_HANDLER_NO_ERR(virtualization_exception_handler, "Virtualization exception"); +EXCEPTION_HANDLER_NO_ERR(security_exception_handler, "Security exception"); + +#endif //EXCEPTION_C \ No newline at end of file diff --git a/kernel/exception_list.c b/kernel/exception_list.c new file mode 100644 index 0000000..c871e5c --- /dev/null +++ b/kernel/exception_list.c @@ -0,0 +1,34 @@ +typedef enum exception_enum { + DIVIDE_BY_ZERO = 0, + DEBUG = 1, + NON_MASKABLE_INTERRUPT = 2, + BREAKPOINT = 3, + OVERFLOW = 4, + BOUND_RANGE_EXCEEDED = 5, + INVALID_OPCODE = 6, + DEVICE_NOT_AVAILABLE = 7, + DOUBLE_FAULT = 8, // Error code = 0 + COPROCESSOR_SEG_OVERRUN = 9, + INVALID_TSS = 10, // Error code = (invalid selector index) + SEGMENT_NOT_PRESENT = 11, // Error code = (segment selector index) + STACK_SEGMENT_FAULT = 12, // Error code = (segment selector index) if invalid ssi, otherwise 0 + GENERAL_PROTECTION_FAULT = 13, // Error code = (segment selector index) if invalid ssi, otherwise 0 + PAGE_FAULT = 14, // Error code = bitmap, see https://wiki.osdev.org/Exceptions#Page_Fault + RESERVED_15 = 15, + X87_FP_EXCEPTION = 16, + ALIGNMENT_CHECK = 17, + MACHINE_CHECK = 18, + SIMD_FP_EXCEPTION = 19, + VIRTUALIZATION_EXCEPTION = 20, + RESERVED_21 = 21, + RESERVED_22 = 22, + RESERVED_23 = 23, + RESERVED_24 = 24, + RESERVED_25 = 25, + RESERVED_26 = 26, + RESERVED_27 = 27, + RESERVED_28 = 28, + RESERVED_29 = 29, + SECURITY_EXCEPTION = 30, + RESERVED_31 = 31 +} exception; \ No newline at end of file diff --git a/kernel/interrupts.c b/kernel/interrupts.c index 895b2b8..57226f4 100644 --- a/kernel/interrupts.c +++ b/kernel/interrupts.c @@ -7,6 +7,8 @@ #include "memory.c" #include "terminal.c" #include "inline_asm.c" +#include "exception.c" +#include "exception_list.c" #include "drivers/keyboard/keyboard.c" typedef struct idt_entry_struct { @@ -17,28 +19,9 @@ typedef struct idt_entry_struct { uint16_t offset_2; // offset bits 16..31 } idt_entry; -struct interrupt_frame { - uint32_t esp; - uint32_t ss; - uint32_t gs; - uint32_t fs; - uint32_t es; - uint32_t ds; - uint32_t ebp; - uint32_t edi; - uint32_t esi; - uint32_t edx; - uint32_t ecx; - uint32_t ebx; - uint32_t eax; - uint32_t eip; - uint32_t cs; - uint32_t eflags; -}; - idt_entry IDT[256]; -void interrupt_new_handler(int intnum, void (*handler)(struct interrupt_frame*)) { +void interrupt_new_handler(int intnum, void (*handler)(interrupt_frame*)) { uint32_t handler_address = (uint32_t) handler; IDT[intnum].offset_1 = (uint16_t) (handler_address & 0xffff); IDT[intnum].selector = 0x08; @@ -68,6 +51,40 @@ void interrupt_init() { outb(0x21 , 0xff); outb(0xA1 , 0xff); + // Exceptions + interrupt_new_handler(DIVIDE_BY_ZERO, divide_by_zero_handler); + interrupt_new_handler(DEBUG, debug_handler); + interrupt_new_handler(NON_MASKABLE_INTERRUPT, non_maskable_interrupt_handler); + interrupt_new_handler(BREAKPOINT, breakpoint_handler); + interrupt_new_handler(OVERFLOW, overflow_handler); + interrupt_new_handler(BOUND_RANGE_EXCEEDED, bound_range_exceeded_handler); + interrupt_new_handler(INVALID_OPCODE, invalid_opcode_handler); + interrupt_new_handler(DEVICE_NOT_AVAILABLE, device_not_available_handler); + interrupt_new_handler(DOUBLE_FAULT, double_fault_handler); + interrupt_new_handler(COPROCESSOR_SEG_OVERRUN, coprocessor_seg_overrun_handler); + interrupt_new_handler(INVALID_TSS, invalid_tss_handler); + interrupt_new_handler(SEGMENT_NOT_PRESENT, segment_not_present_handler); + interrupt_new_handler(STACK_SEGMENT_FAULT, stack_segment_fault_handler); + interrupt_new_handler(GENERAL_PROTECTION_FAULT, general_protection_fault_handler); + interrupt_new_handler(PAGE_FAULT, page_fault_handler); + interrupt_new_handler(RESERVED_15, reserved_handler); + interrupt_new_handler(X87_FP_EXCEPTION, x87_fp_exception_handler); + interrupt_new_handler(ALIGNMENT_CHECK, alignment_check_handler); + interrupt_new_handler(MACHINE_CHECK, machine_check_handler); + interrupt_new_handler(SIMD_FP_EXCEPTION, simd_fp_exception_handler); + interrupt_new_handler(VIRTUALIZATION_EXCEPTION, virtualization_exception_handler); + interrupt_new_handler(RESERVED_21, reserved_handler); + interrupt_new_handler(RESERVED_22, reserved_handler); + interrupt_new_handler(RESERVED_23, reserved_handler); + interrupt_new_handler(RESERVED_24, reserved_handler); + interrupt_new_handler(RESERVED_25, reserved_handler); + interrupt_new_handler(RESERVED_26, reserved_handler); + interrupt_new_handler(RESERVED_27, reserved_handler); + interrupt_new_handler(RESERVED_28, reserved_handler); + interrupt_new_handler(RESERVED_29, reserved_handler); + interrupt_new_handler(SECURITY_EXCEPTION, security_exception_handler); + interrupt_new_handler(RESERVED_31, reserved_handler); + interrupt_new_handler(0x21, keyboard_handler); uint16_t size = (sizeof(idt_entry) * 256); diff --git a/kernel/terminal.c b/kernel/terminal.c index 1299194..1b242f9 100644 --- a/kernel/terminal.c +++ b/kernel/terminal.c @@ -4,7 +4,7 @@ #include #include #include - + static const size_t VGA_WIDTH = 80; static const size_t VGA_HEIGHT = 25; @@ -94,7 +94,7 @@ void terminal_writestring(const char* data) { terminal_write(data, strlen(data)); } -char* itoa(int value, char* result, int base) { +char* itoa(unsigned int value, char* result, int base) { // check that the base if valid if (base < 2 || base > 36) { *result = '\0'; return result; } @@ -107,8 +107,6 @@ char* itoa(int value, char* result, int base) { *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)]; } while ( value ); - // Apply negative sign - if (tmp_value < 0) *ptr++ = '-'; *ptr-- = '\0'; while(ptr1 < ptr) { tmp_char = *ptr; @@ -118,4 +116,10 @@ char* itoa(int value, char* result, int base) { return result; } +void terminal_writeint(int number, int base) { + char* result = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; + itoa(number, result, base); + terminal_writestring(result); +} + #endif //TERMINAL_C \ No newline at end of file