diff --git a/Makefile b/Makefile index 0ceaa68..d971fe3 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ CC = i686-elf-gcc -DEBUG_FLAGS = -D__TESTING__ -g -Wno-div-by-zero +DEBUG_FLAGS = -D__TESTING__ -g CFLAGS = -m32 -ffreestanding -Wall -Wextra -Werror -Wpedantic --sysroot=$(PWD)/sysroot -isystem=/usr/include -Iinclude -MD $(DEBUG_FLAGS) @@ -39,7 +39,7 @@ all: kernel.elf env: install-headers install-libs # TODO: change this to a file specific target, so it doesnt recompile everytime, and so we can move as a prereq on kernel.elf util/./gen-clangd.sh -kernel.elf: install-headers install-libs $(c_kern_objects) $(asm_kern_objects) +kernel.elf: install-headers install-libs env $(c_kern_objects) $(asm_kern_objects) $(CC) $(CFLAGS) -T $(shell find . -name "link.ld") -o $@ $(c_kern_objects) $(asm_kern_objects) -nostdlib -lk -lgcc os.iso: kernel.elf diff --git a/TODO.md b/TODO.md index d2f5cc2..755759a 100644 --- a/TODO.md +++ b/TODO.md @@ -1,7 +1,6 @@ ## What do I need to do? -Exception handling is a must for next part, we need to be able to dianogse issues better +### Features I want - - Want the address of the fault - - Proper handling of the issue - - Maybe dump registers? +- A kernel bus + - some kind of driver where I can send messages that can eventually be accessed globally by other drives / applications diff --git a/kernel/arch/idt/idt.c b/kernel/arch/idt/idt.c index a688f3f..eb185fb 100644 --- a/kernel/arch/idt/idt.c +++ b/kernel/arch/idt/idt.c @@ -1,10 +1,9 @@ +#include #include #include - -#ifdef __TESTING__ -#include #include -#endif + +#include #include #include #include @@ -19,21 +18,218 @@ static bool vectors[IDT_MAX_DESCRIPTORS]; extern struct keyboard_state keyb_state; -void exception_handler(struct cpu_state __attribute__((unused)) cpu, uint32_t interrupt, struct stack_state stack) + +#define EXTERNAL_BIT (0x1) + +#define TBL_GDT (0x0) +#define TBL_LDT (0x2) +#define TBL_IDT (0x1) +#define TBL_IDT_TWO (0x3) + +static void examine_selector(uint32_t selector) { - printf("%1 %2\n", interrupt, stack.eflags); - if (interrupt <= 31) { // TODO: implement proper handling for each exception, also implement the proper gates & error code checking -#ifdef __TESTING__ - kerror("EXCEPTION"); - printf("Exeption: %2\n", interrupt); -#endif - //__asm__ volatile ("cli; hlt"); // hangs the computer + printf("The interrupt arised %s.\n", (selector & EXTERNAL_BIT) == EXTERNAL_BIT ? "externally" : "internally"); + + + printf("The descriptor 0x%x, is located in the ", selector, (selector & 0x0000FFFF) >> 3); + if ((((selector >> 1) & TBL_IDT) == TBL_IDT) + || ((selector >> 1) & TBL_IDT_TWO) == TBL_IDT_TWO) { + puts("IDT."); + + } else if (((selector >> 1) & TBL_LDT) == TBL_LDT) { + puts("LDT."); + } else { + puts("GDT."); + } + + return; +} + +#undef TBL_GDT +#undef TBL_LDT +#undef TBL_IDT +#undef TBL_IDT_TWO + +#define PF_P (1 << 0) +#define PF_W (1 << 1) +#define PF_U (1 << 2) +#define PF_R (1 << 3) +#define PF_I (1 << 4) +#define PF_PK (1 << 5) +#define PF_SS (1 << 6) +#define PF_SGX (1 << 15) +static void examine_page_fault(uint32_t error_code) +{ + puts("Page fault:"); + if (error_code & PF_P) { + puts("Page-protection violation."); + } else { + puts("Not present page."); } - if (interrupt == PIC_KEYB) { - unsigned char in = inb(0x60); - do_keypress(decode_scancode(in)); - PIC_sendEOI(1); + if (error_code & PF_W) { + puts("Write access."); + } else { + puts("Read access."); + } + + if (error_code & PF_U) { + puts("In CPL 3."); + } + + if (error_code & PF_R) { // Only applies if PSE or PAE are set in CR4 + puts("One or more page directory entires contain reserved bits which are set to 1."); + } + + if (error_code & PF_I) { // Only applicable when the No-Execute bit is supported and enabled + puts("Instruction fetch."); + } + + if (error_code & PF_PK) { + puts("Protection-key violation"); //TODO PRKU (user mode access) or PRKS MSR (supervisor mode access) specifies the key rights + } + + if (error_code & PF_SS) { + puts("Shadow stack access."); + } + + if (error_code & PF_SGX) { // Unrelated to ordinary paging + puts("SGX vioilation"); + } + + // TODO, also sets CR2 reg to the virtual address which caused the page fault +} +#undef PF_P +#undef PF_W +#undef PF_U +#undef PF_R +#undef PF_I +#undef PF_PK +#undef PF_SS +#undef PF_SGX + +#define EXCEPTION_LOCATION() printf("Exception occurred at 0x%2\n", stack.eip) + +void exception_handler(struct cpu_state __attribute__((unused)) cpu, uint32_t interrupt, struct stack_state stack) +{ + uint32_t inbyte; + switch (interrupt) { + /** EXCEPTIONS BEGIN **/ + case EXCEPT_DIV_ERR: + kerror("EXCEPTION: DIV BY ZERO"); + EXCEPTION_LOCATION(); + break; + case EXCEPT_DEBUG: + kinfo("EXCEPTION: DEBUG"); // TODO: this one has more specific requirements + break; + case EXCEPT_NMI: + kinfo("EXCEPTION: NON-MASKABLE INTERRUPT"); // TODO + break; + case EXCEPT_BREAKPOINT: + kinfo("EXCEPTION: BREAKPOINT"); + // TODO + break; + case EXCEPT_OVERFLOW: + kerror("EXCEPTION: OVERFLOW"); + break; + case EXCEPT_BOUND_RANGE_EXCEEDED: + kerror("EXCEPTION: BOUND RANGE EXCEEDED"); + EXCEPTION_LOCATION(); + break; + case EXCEPT_INVALID_OPCODE: + kerror("EXCEPTION: INVALID OPCODE"); + EXCEPTION_LOCATION(); + break; + case EXCEPT_DEVICE_NOT_AVAILABLE: + kerror("EXCEPTION: DEVICE NOT AVAILABLE"); + printf("Instructions expecting an FPU were used, but no FPU was found. Is it disabled in CR0? Do you have an FPU?\n"); + EXCEPTION_LOCATION(); + break; + case EXCEPT_DOUBLE_FAULT: + kerror("EXCEPTION: DOUBLE FAULT"); + __asm__ volatile ("cli; hlt"); // boned + break; + case EXCEPT_INVALID_TSS: + kerror("EXCEPTION: INVALID TSS"); + examine_selector(stack.error_code); + // TODO: when i implement the TSS, the EIP will be one of two things + // if this occurs before loading segmenet selectors from the TSS, EIP will be the instruction that caused the instruction + // otherwise its the first instruction in the new task + break; + case EXCEPT_SEG_NOT_PRESENT: + kerror("EXCEPTION: SEGMENT NOT PRESENT"); + EXCEPTION_LOCATION(); + examine_selector(stack.error_code); + break; + case EXCEPT_STACK_SEG_FAULT: + kerror("EXCEPTION: STACK-SEGMENT FAULT"); + if (stack.error_code == 0) { + EXCEPTION_LOCATION(); + } else { + printf("Tried loading non-present stack segment during hardware task switch.\n"); + examine_selector(stack.error_code); + } + break; + case EXCEPT_GENERAL_PROTECTION: + kerror("EXCEPTION: GENERAL PROTECTION FAULT"); + EXCEPTION_LOCATION(); + if (stack.error_code != 0) + examine_selector(stack.error_code); + break; + case EXCEPT_PAGE_FAULT: + kerror("EXCEPTION: PAGE FAULT"); + EXCEPTION_LOCATION(); + examine_page_fault(stack.error_code); + break; + case EXCEPT_FLOATING_POINT_ERR_FPU: + kerror("EXCEPTION: FLOATING POINT ERROR FPU"); + // TODO: this requires a custom handler, it needs another register + break; + case EXCEPT_ALIGNMENT_CHECK: + kerror("EXCEPTION: ALIGNMENT CHECK"); + + // TODO: only in CPL3 + break; + case EXCEPT_MACHINE_CHECK: + kerror("EXCEPTION: MACHINE CHECK"); + // TODO disabled by default + break; + case EXCEPT_FLOATING_POINT_ERR_SIMD: + kerror("EXCEPTION: FLOATING POINT ERROR SIMD"); + // TODO disabled by default + break; + case EXCEPT_VIRT: + kerror("EXCEPTION: VIRTUALIZATION"); + break; + case EXCEPT_CTRL_PROT: + kerror("EXCEPTION: CONTROL PROTECTION"); + printf("Error code: 0x%2\n", stack.error_code); + break; + case EXCEPT_HYPERVISOR_INJECTION: + kerror("EXCEPTION: HYPERVISOR INJECTION"); + break; + case EXCEPT_VMM_COMMUNICATION: + kerror("EXCEPTION: VMM COMMUNICATION"); + printf("Error code: 0x%2\n", stack.error_code); + break; + case EXCEPT_SECURITY_EXCEPTION: + kerror("EXCEPTION: SECURITY"); + printf("Error code: 0x%2\n", stack.error_code); + break; + /** EXCEPTIONS END **/ + + /** PIC BEGIN **/ + case PIC_KEYB: + inbyte = inb(0x60); + do_keypress(decode_scancode(inbyte)); + PIC_sendEOI(1); + break; + + /** PIC END **/ + default: + kerror("EXCEPTION: UNHANDLED EXCEPTION OR INTERRUPT"); + printf("Error code: 0x%2\n", stack.error_code); + break; } } @@ -68,7 +264,7 @@ void idt_init(void) PIC_remap(0x20, 0x28); pic_disable(); // mask everything IRQ_clear_mask(1); - + __asm__ volatile("sti"); // set the interrupt flag #ifdef __TESTING__ kinfo("Initialized the IDT"); diff --git a/kernel/arch/idt/idt_src.s b/kernel/arch/idt/idt_src.s index 469c920..3e72558 100644 --- a/kernel/arch/idt/idt_src.s +++ b/kernel/arch/idt/idt_src.s @@ -3,14 +3,6 @@ extern exception_handler_err %macro isr_err_stub 1 isr_stub_%+%1: - ;pushad - ;cld - ;push dword %1 - ;call exception_handler_err - ;pop eax ; pop the error - ;pop eax ; make sure to pop off the dword!! - ;popad - ;iret push dword %1 ; push the interrupt number jmp common_interrupt_handler @@ -18,13 +10,6 @@ isr_stub_%+%1: %macro isr_no_err_stub 1 isr_stub_%+%1: - ;pushad - ;cld - ;push dword %1 - ;call exception_handler - ;pop eax - ;popad - ;iret push dword 0 push dword %1 jmp common_interrupt_handler @@ -51,7 +36,8 @@ common_interrupt_handler: pop ebx pop eax - ; restore the esp + ; lets move the stack before the error code and interrupt number + ; since we don't want these to be popped anywhere add esp, 8 iret diff --git a/kernel/include/kernel/x86/idt.h b/kernel/include/kernel/x86/idt.h index 64e10e4..2f290f8 100644 --- a/kernel/include/kernel/x86/idt.h +++ b/kernel/include/kernel/x86/idt.h @@ -15,7 +15,6 @@ #define EXCEPT_INVALID_OPCODE 6 #define EXCEPT_DEVICE_NOT_AVAILABLE 7 #define EXCEPT_DOUBLE_FAULT 8 -#define EXCEPT_SEG_OVERRUN 9 #define EXCEPT_INVALID_TSS 10 #define EXCEPT_SEG_NOT_PRESENT 11 #define EXCEPT_STACK_SEG_FAULT 12 @@ -27,6 +26,9 @@ #define EXCEPT_FLOATING_POINT_ERR_SIMD 19 #define EXCEPT_VIRT 20 #define EXCEPT_CTRL_PROT 21 +#define EXCEPT_HYPERVISOR_INJECTION 28 +#define EXCEPT_VMM_COMMUNICATION 29 +#define EXCEPT_SECURITY_EXCEPTION 30 struct cpu_state { uint32_t eax;