diff --git a/.gdbinit b/.gdbinit index f2f4e79..819a9d6 100644 --- a/.gdbinit +++ b/.gdbinit @@ -1,6 +1,13 @@ set architecture i386:x86-64 # AT&T syntax is awful set disassembly-flavor intel + +# Pretty-printing :) +enable pretty-printer + +# Cool layout +layout split + file Kernel/Arch/x86_64-pc/BlobOS.elf target remote :1234 diff --git a/Kernel/Arch/x86_64-pc/Entry/Entry.c b/Kernel/Arch/x86_64-pc/Entry/Entry.c index 8db86c9..15fed66 100644 --- a/Kernel/Arch/x86_64-pc/Entry/Entry.c +++ b/Kernel/Arch/x86_64-pc/Entry/Entry.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -10,6 +11,8 @@ #define GIT_VERSION "Undefined" #endif +extern void far_jump(void); + // The Limine requests can be placed anywhere, but it is important that // the compiler does not optimise them away, so, usually, they should // be made volatile or equivalent. @@ -47,20 +50,39 @@ void Arch_entry(void) { GDT_Init(); kprintf("GDT (Re)-loaded!\n"); - IDT_Init(); - kprintf("IDT Loaded!\n"); + reloadSegments(); + kprintf("Data and code segment registers reloaded!\n"); // IRQ0 starts at 0x20 and IRQ8 starts at 0x28. PIC_Initialize(0x20, 0x28); - PIC_Mask(ALL); kprintf("PIC remapped to 0x20 and 0x28\n"); + PIC_Mask(ALL); + + Load_Exceptions(); + kprintf("Exceptions Loaded!\n"); + + IDT_Init(); + kprintf("IDT Loaded!\n"); sti(); kprintf("Interrupts enabled!\n"); + // PIC_Unmask(TIMER); + + asm("int $0"); + asm("int $0"); + asm("int $0"); + asm("int $0"); + asm("int $0"); + asm("int $35"); + asm("int $0"); + asm("int $0"); + asm("int $0"); + asm("int $0"); + asm("int $0"); + #ifdef GIT_VERSION kprintf("Welcome to BlobOS!\nVersion: %s\n", GIT_VERSION); #endif - // asm("int $0x01"); halt(); } diff --git a/Kernel/Arch/x86_64-pc/Include/System/IDT.h b/Kernel/Arch/x86_64-pc/Include/System/IDT.h index 15fb35c..1a5e5ad 100644 --- a/Kernel/Arch/x86_64-pc/Include/System/IDT.h +++ b/Kernel/Arch/x86_64-pc/Include/System/IDT.h @@ -3,6 +3,10 @@ #define IDT_MAX_DESCRIPTORS 256 +#define IDT_FLAGS_INTERRUPT_GATE 0x8E +#define IDT_FLAGS_TRAP_GATE 0x8F + +void IDT_Add_Int(uint8_t vector, void (*isr)(), uint8_t flags); void IDT_Init(void); // 64-bit IDT Entry. diff --git a/Kernel/Arch/x86_64-pc/Include/System/ISR.h b/Kernel/Arch/x86_64-pc/Include/System/Interrupts.h similarity index 58% rename from Kernel/Arch/x86_64-pc/Include/System/ISR.h rename to Kernel/Arch/x86_64-pc/Include/System/Interrupts.h index 23c7a16..3098ed5 100644 --- a/Kernel/Arch/x86_64-pc/Include/System/ISR.h +++ b/Kernel/Arch/x86_64-pc/Include/System/Interrupts.h @@ -1,12 +1,20 @@ #pragma once #include +struct interrupt_frame { + uint64_t ip; + uint64_t cs; + uint64_t flags; + uint64_t sp; + uint64_t ss; +}; + typedef struct { uint64_t r15, r14, r13, r12, r11, r10, r9, r8; uint64_t rdi, rsi, rbx, rdx, rcx, rax; - uint64_t interrupt, error; + uint64_t error; } __attribute__((packed)) Registers; typedef void (*ISRHandler)(Registers *regs); -void isr_register_handler(int interrupt, ISRHandler handler); +void Load_Exceptions(void); diff --git a/Kernel/Arch/x86_64-pc/Include/System/PIC.h b/Kernel/Arch/x86_64-pc/Include/System/PIC.h index 9c96008..3418b70 100644 --- a/Kernel/Arch/x86_64-pc/Include/System/PIC.h +++ b/Kernel/Arch/x86_64-pc/Include/System/PIC.h @@ -5,23 +5,26 @@ /* * IRQ macros */ -#define ALL 0xFF -#define TIMER 0 -#define KEYBOARD 1 -#define CASCADE 2 -#define COM2_4 3 -#define COM1_3 4 -#define LPT 5 -#define FLOPPY 6 -#define FREE7 7 -#define CLOCK 8 -#define FREE9 9 -#define FREE10 10 -#define FREE11 11 -#define PS2MOUSE 12 -#define COPROC 13 -#define IDE_1 14 -#define IDE_2 15 + +enum Interrupts { + ALL = 0xFF, + TIMER = 0, + KEYBOARD, + CASCADE, + COM2_4, + COM1_3, + LPT, + FLOPPY, + FREE7, + CLOCK, + FREE9, + FREE10, + FREE11, + PS2MOUSE, + COPROC, + IDE_1, + IDE_2 +}; /* * Functions diff --git a/Kernel/Arch/x86_64-pc/System/GDTFarJump.asm b/Kernel/Arch/x86_64-pc/System/GDTFarJump.asm new file mode 100644 index 0000000..6926079 --- /dev/null +++ b/Kernel/Arch/x86_64-pc/System/GDTFarJump.asm @@ -0,0 +1,17 @@ +[bits 64] +[global reloadSegments] + +reloadSegments: + push 0x08 ; Push code segment to stack + lea rax, [rel .reload_CS] ; Load address of .reload_CS into RAX + push rax ; Push this value to the stack + retfq ; Perform a far return + .reload_CS: + ; Reload data segment registers + mov ax, 0x10 ; 0x10 is the 64-bit data segment + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + ret diff --git a/Kernel/Arch/x86_64-pc/System/IDT.c b/Kernel/Arch/x86_64-pc/System/IDT.c index 6d47e34..9a812c0 100644 --- a/Kernel/Arch/x86_64-pc/System/IDT.c +++ b/Kernel/Arch/x86_64-pc/System/IDT.c @@ -2,11 +2,9 @@ #include #include -extern uint64_t isr_stub_table[]; - __attribute__((aligned(0x10))) static idt_entry_t idt[256]; static idtr_t idtr; -void idt_set_descriptor(uint8_t vector, uintptr_t isr, uint8_t flags) { +void IDT_Add_Int(uint8_t vector, void (*isr)(), uint8_t flags) { idt_entry_t *descriptor = &idt[vector]; descriptor->isr_low = (uint64_t)isr & 0xFFFF; @@ -22,9 +20,5 @@ void IDT_Init(void) { idtr.base = (uintptr_t)&idt[0]; idtr.limit = (uint16_t)sizeof(idt_entry_t) * IDT_MAX_DESCRIPTORS - 1; - for (uint8_t vector = 0; vector < 256; vector++) { - idt_set_descriptor(vector, isr_stub_table[vector], 0x8E); - } - __asm__ volatile("lidt %0" : : "m"(idtr)); // load the new IDT } diff --git a/Kernel/Arch/x86_64-pc/System/Interrupts.c b/Kernel/Arch/x86_64-pc/System/Interrupts.c new file mode 100644 index 0000000..7091f3b --- /dev/null +++ b/Kernel/Arch/x86_64-pc/System/Interrupts.c @@ -0,0 +1,109 @@ +#include +#include +#include +#include + +__attribute__((interrupt)) void C_Int_0(struct interrupt_frame *frame) { + kprintf("Divide By Zero Error #00\n"); +} + +__attribute__((interrupt)) void C_Int_1(struct interrupt_frame *frame) { + panic("Debug Error #DB"); +} +__attribute__((interrupt)) void C_Int_2(struct interrupt_frame *frame) { + panic("NMI Interrupt #--"); +} +__attribute__((interrupt)) void C_Int_3(struct interrupt_frame *frame) { + panic("Breakpoint #BP"); +} +__attribute__((interrupt)) void C_Int_4(struct interrupt_frame *frame) { + panic("Overflow #OF"); +} +__attribute__((interrupt)) void C_Int_5(struct interrupt_frame *frame) { + panic("BOUND Range Exceeded #BR"); +} +__attribute__((interrupt)) void C_Int_6(struct interrupt_frame *frame) { + panic("Invalid Opcode #UD"); +} +__attribute__((interrupt)) void C_Int_7(struct interrupt_frame *frame) { + panic("Device Not Available #NM"); +} +__attribute__((interrupt)) void C_Int_8(struct interrupt_frame *frame, + uint64_t error_code) { + panic("Double Fault #DF"); +} +__attribute__((interrupt)) void C_Int_9(struct interrupt_frame *frame) { + panic("Coprocessor Segment Overrun #NA"); +} +__attribute__((interrupt)) void C_Int_10(struct interrupt_frame *frame, + uint64_t error_code) { + panic("Invalid TSS #TS"); +} +__attribute__((interrupt)) void C_Int_11(struct interrupt_frame *frame, + uint64_t error_code) { + panic("Segment Not Present #NP"); +} +__attribute__((interrupt)) void C_Int_12(struct interrupt_frame *frame, + uint64_t error_code) { + panic("Stack Segment Fault #SS"); +} +__attribute__((interrupt)) void C_Int_13(struct interrupt_frame *frame, + uint64_t error_code) { + kprintf("%p", error_code); + asm("hlt"); + // panic("General Protection Fault #GP"); +} +__attribute__((interrupt)) void C_Int_14(struct interrupt_frame *frame, + uint64_t error_code) { + uint64_t *faultAddress; + asm volatile("mov %%cr2, %0" : "=r"(faultAddress)::"memory"); + kprintf("%p", faultAddress); + // panic("Page Fault #PF"); +} +__attribute__((interrupt)) void C_Int_16(struct interrupt_frame *frame) { + panic("FPU Floating-Point Error #MF"); +} +__attribute__((interrupt)) void C_Int_17(struct interrupt_frame *frame, + uint64_t error_code) { + panic("Alignment Check #AC"); +} +__attribute__((interrupt)) void C_Int_18(struct interrupt_frame *frame) { + panic("Machine Check #MC"); +} +__attribute__((interrupt)) void C_Int_19(struct interrupt_frame *frame) { + panic("SIMD Floating-Point #XF"); +} + +// 20 to 31 are Intel reserved. + +__attribute__((interrupt)) void +Default_INT_Handler(struct interrupt_frame *frame) { + kprintf("Unhandled interrupt!\n"); +} + +void Load_Exceptions(void) { + IDT_Add_Int(0, C_Int_0, IDT_FLAGS_INTERRUPT_GATE); + IDT_Add_Int(1, C_Int_1, IDT_FLAGS_INTERRUPT_GATE); + IDT_Add_Int(2, C_Int_2, IDT_FLAGS_INTERRUPT_GATE); + IDT_Add_Int(3, C_Int_3, IDT_FLAGS_INTERRUPT_GATE); + IDT_Add_Int(4, C_Int_4, IDT_FLAGS_INTERRUPT_GATE); + IDT_Add_Int(5, C_Int_5, IDT_FLAGS_INTERRUPT_GATE); + IDT_Add_Int(6, C_Int_6, IDT_FLAGS_INTERRUPT_GATE); + IDT_Add_Int(7, C_Int_7, IDT_FLAGS_INTERRUPT_GATE); + IDT_Add_Int(8, C_Int_8, IDT_FLAGS_INTERRUPT_GATE); + IDT_Add_Int(9, C_Int_9, IDT_FLAGS_INTERRUPT_GATE); + IDT_Add_Int(10, C_Int_10, IDT_FLAGS_INTERRUPT_GATE); + IDT_Add_Int(11, C_Int_11, IDT_FLAGS_INTERRUPT_GATE); + IDT_Add_Int(12, C_Int_12, IDT_FLAGS_INTERRUPT_GATE); + IDT_Add_Int(13, C_Int_13, IDT_FLAGS_INTERRUPT_GATE); + IDT_Add_Int(14, C_Int_14, IDT_FLAGS_INTERRUPT_GATE); + // 15 is Intel reserved. + IDT_Add_Int(15, Default_INT_Handler, IDT_FLAGS_INTERRUPT_GATE); + IDT_Add_Int(16, C_Int_16, IDT_FLAGS_INTERRUPT_GATE); + IDT_Add_Int(17, C_Int_17, IDT_FLAGS_INTERRUPT_GATE); + IDT_Add_Int(18, C_Int_18, IDT_FLAGS_INTERRUPT_GATE); + IDT_Add_Int(19, C_Int_19, IDT_FLAGS_INTERRUPT_GATE); + for (uint8_t i = 20; i < 255; i++) { + IDT_Add_Int(i, Default_INT_Handler, IDT_FLAGS_INTERRUPT_GATE); + } +} diff --git a/Kernel/Kernel/Panic.c b/Kernel/Kernel/Panic.c index ebb1f85..ca6ac0a 100644 --- a/Kernel/Kernel/Panic.c +++ b/Kernel/Kernel/Panic.c @@ -1,76 +1,15 @@ #include #include -#include #include #include #include -void get_all_registers() { - uint64_t rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp, r8, r9, r10, r11, r12, r13, - r14, r15; - - // Inline assembly to read registers - asm volatile("movq %%rax, %0\n" - "movq %%rbx, %1\n" - "movq %%rcx, %2\n" - "movq %%rdx, %3\n" - "movq %%rsi, %4\n" - "movq %%rdi, %5\n" - "movq %%rsp, %6\n" - "movq %%rbp, %7\n" - "movq %%r8, %8\n" - "movq %%r9, %9\n" - "movq %%r10, %10\n" - "movq %%r11, %11\n" - "movq %%r12, %12\n" - "movq %%r13, %13\n" - "movq %%r14, %14\n" - "movq %%r15, %15\n" - : "=m"(rax), "=m"(rbx), "=m"(rcx), "=m"(rdx), "=m"(rsi), - "=m"(rdi), "=m"(rsp), "=m"(rbp), "=m"(r8), "=m"(r9), - "=m"(r10), "=m"(r11), "=m"(r12), "=m"(r13), "=m"(r14), - "=m"(r15)); - kprintf("\nRegisters: \nRAX: %p" - " | RBX: %p" - " | RCX: %p\n" - "RDX: %p" - " | RSI: %p" - " | RDI: %p" - " | RSP: %p\n" - "RBP: %p" - " | R8: %p" - " | R9: %p\n" - "R10: %p" - " | R11: %p" - " | R12: %p\n" - "R13: %p" - " | R14: %p" - " | R15: %p" - " |\n", - rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp, r8, r9, r10, r11, r12, r13, - r14, r15); -} - struct stackframe { struct stackframe *rbp; uint64_t rip; }; -// FIXME: Not exactly the stack trace, it's just for the panic not to be -// empty... -// TODO: Get the function names. -void get_stack_trace(unsigned int MaxFrames) { - struct stackframe *stk; - stk = __builtin_frame_address(0); - kprintf("\nStack trace:\n"); - for (unsigned int frame = 0; stk && frame < MaxFrames; ++frame) { - if (stk->rip == 0) - break; - kprintf("Frame %d: RIP %p \n", frame, (void *)stk->rip); - stk = stk->rbp; - } -} - +// TODO: Unwind the stack and get a cool stack trace :) void panic(char *message) { framebuffer_clear(0xcccccc, 0xc40404); kprintf( @@ -78,8 +17,6 @@ void panic(char *message) { "file an issue to https://github.com/RedsonBr140/BlobOS/issues " "with detailed information.\nYou will need to restart your " "computer.\n"); - get_stack_trace(5); - get_all_registers(); kprintf("\nError message: %s\n", message); hcf();