Skip to content

Commit

Permalink
refactor: Doing Interrupts in C, no Assembly needed.
Browse files Browse the repository at this point in the history
  • Loading branch information
RedsonBr140 committed Nov 4, 2023
1 parent e4d4bfe commit e1f8757
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 94 deletions.
7 changes: 7 additions & 0 deletions .gdbinit
Original file line number Diff line number Diff line change
@@ -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
30 changes: 26 additions & 4 deletions Kernel/Arch/x86_64-pc/Entry/Entry.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
#include <LibK/stdio.h>
#include <Serial/Serial.h>
#include <System/GDT.h>
#include <System/Interrupts.h>
#include <System/PIC.h>
#include <limine.h>

#ifndef GIT_VERSION
#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.
Expand Down Expand Up @@ -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();
}
4 changes: 4 additions & 0 deletions Kernel/Arch/x86_64-pc/Include/System/IDT.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
#pragma once
#include <stdint.h>

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);
37 changes: 20 additions & 17 deletions Kernel/Arch/x86_64-pc/Include/System/PIC.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
17 changes: 17 additions & 0 deletions Kernel/Arch/x86_64-pc/System/GDTFarJump.asm
Original file line number Diff line number Diff line change
@@ -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
8 changes: 1 addition & 7 deletions Kernel/Arch/x86_64-pc/System/IDT.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@
#include <Kernel/Panic.h>
#include <System/IDT.h>

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;
Expand All @@ -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
}
109 changes: 109 additions & 0 deletions Kernel/Arch/x86_64-pc/System/Interrupts.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#include <Kernel/Panic.h>
#include <LibK/stdio.h>
#include <System/IDT.h>
#include <System/Interrupts.h>

__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);
}
}
65 changes: 1 addition & 64 deletions Kernel/Kernel/Panic.c
Original file line number Diff line number Diff line change
@@ -1,85 +1,22 @@
#include <Asm/Asm.h>
#include <Framebuffer/Framebuffer.h>
#include <IO/Ports.h>
#include <Kernel/Panic.h>
#include <LibK/stdio.h>
#include <stdint.h>

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(
"BlobOS encountered an error which it couldn't recover from.\nPlease "
"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();
Expand Down

0 comments on commit e1f8757

Please sign in to comment.