feat: idt
This commit is contained in:
parent
65a0eb1cda
commit
880638202f
|
@ -4,6 +4,10 @@
|
|||
|
||||
Res hal_setup(void);
|
||||
|
||||
/* --- Structs ------------------------------------------------------------ */
|
||||
|
||||
typedef struct _HalRegs HalRegs;
|
||||
|
||||
/* --- Assembly function --------------------------------------------------- */
|
||||
|
||||
void hal_disable_interrupts(void);
|
||||
|
@ -16,4 +20,4 @@ void hal_panic(void);
|
|||
|
||||
/* --- I/O ---------------------------------------------------------------- */
|
||||
|
||||
Stream hal_dbg_stream(void);
|
||||
Stream hal_dbg_stream(void);
|
||||
|
|
8
src/kernel/archs/x86_64/asm.h
Normal file
8
src/kernel/archs/x86_64/asm.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#define asm_read_cr(n, reg) asm volatile("mov %%cr" #n ", %0" \
|
||||
: "=r"(reg))
|
||||
|
||||
#define asm_write_cr(n, reg) asm volatile("mov %0, %%cr" #n \
|
||||
: \
|
||||
: "r"(reg))
|
112
src/kernel/archs/x86_64/handler.c
Normal file
112
src/kernel/archs/x86_64/handler.c
Normal file
|
@ -0,0 +1,112 @@
|
|||
#include <dbg/log.h>
|
||||
#include <hal.h>
|
||||
#include <sync/spinlock.h>
|
||||
|
||||
#include "asm.h"
|
||||
#include "regs.h"
|
||||
|
||||
enum
|
||||
{
|
||||
IRQ0 = 32,
|
||||
};
|
||||
|
||||
static Spinlock lock = SPINLOCK_INIT;
|
||||
static char *exception_messages[32] = {
|
||||
"Division By Zero",
|
||||
"Debug",
|
||||
"Non Maskable Interrupt",
|
||||
"Breakpoint",
|
||||
"Detected Overflow",
|
||||
"Out Of Bounds",
|
||||
"Invalid Opcode",
|
||||
"No Coprocessor",
|
||||
"Double Fault",
|
||||
"Coprocessor Segment Overrun",
|
||||
"Bad Tss",
|
||||
"Segment Not Present",
|
||||
"StackFault",
|
||||
"General Protection Fault",
|
||||
"Page Fault",
|
||||
"Unknown Interrupt",
|
||||
"Coprocessor Fault",
|
||||
"Alignment Check",
|
||||
"Machine Check",
|
||||
"SIMD Floating-Point Exception",
|
||||
"Virtualization Exception",
|
||||
"Control Protection Exception",
|
||||
"Reserved",
|
||||
"Hypervisor Injection Exception",
|
||||
"VMM Communication Exception",
|
||||
"Security Exception",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
};
|
||||
|
||||
static void dump_backtrace(uintptr_t rbp)
|
||||
{
|
||||
struct _StackFrame
|
||||
{
|
||||
struct _StackFrame *rbp;
|
||||
uint64_t rip;
|
||||
} *stackframe = (void *)rbp;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (stackframe->rip == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
print$(" * %p\n", stackframe->rip);
|
||||
stackframe = stackframe->rbp;
|
||||
}
|
||||
}
|
||||
|
||||
static void kpanic(HalRegs const regs[static 1])
|
||||
{
|
||||
spinlock_acquire(&lock);
|
||||
uint64_t cr0, cr2, cr3, cr4;
|
||||
|
||||
asm_read_cr(0, cr0);
|
||||
asm_read_cr(2, cr2);
|
||||
asm_read_cr(3, cr3);
|
||||
asm_read_cr(4, cr4);
|
||||
|
||||
print$("\n!!! ---------------------------------------------------------------------------------------------------\n\n");
|
||||
print$(" KERNEL PANIC\n");
|
||||
print$(" %s was raised\n\n", exception_messages[regs->intno]);
|
||||
print$(" Registers:\n");
|
||||
print$(" interrupt: %x, err: %x \n", regs->intno, regs->err);
|
||||
print$(" RAX %p RBX %p RCX %p RDX %p\n", regs->rax, regs->rbx, regs->rcx, regs->rdx);
|
||||
print$(" RSI %p RDI %p RBP %p RSP %p\n", regs->rsi, regs->rdi, regs->rbp, regs->rsp);
|
||||
print$(" R8 %p R9 %p R10 %p R11 %p\n", regs->r8, regs->r9, regs->r10, regs->r11);
|
||||
print$(" R12 %p R13 %p R14 %p R15 %p\n", regs->r12, regs->r13, regs->r14, regs->r15);
|
||||
print$(" CR0 %p CR2 %p CR3 %p CR4 %p\n", cr0, cr2, cr3, cr4);
|
||||
print$(" CS %p SS %p FLG %p\n", regs->cs, regs->ss, regs->rflags);
|
||||
print$(" RIP \033[7m%p\033[0m\n\n", regs->rip);
|
||||
print$(" Backtrace:\n");
|
||||
dump_backtrace(regs->rbp);
|
||||
print$("--------------------------------------------------------------------------------------------------- !!!\n\n");
|
||||
spinlock_release(&lock);
|
||||
}
|
||||
|
||||
uintptr_t interrupt_handler(uintptr_t rsp)
|
||||
{
|
||||
HalRegs *regs = (HalRegs *)rsp;
|
||||
|
||||
if (regs->intno < IRQ0)
|
||||
{
|
||||
kpanic(regs);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
hal_disable_interrupts();
|
||||
hal_pause();
|
||||
}
|
||||
}
|
||||
|
||||
return rsp;
|
||||
}
|
|
@ -15,8 +15,99 @@ gdt_flush:
|
|||
push %rdi
|
||||
lretq
|
||||
|
||||
|
||||
tss_flush:
|
||||
mov $0x28, %ax
|
||||
ltr %ax
|
||||
ret
|
||||
|
||||
.altmacro
|
||||
.globl idt_flush
|
||||
.globl __interrupts_vector
|
||||
.extern interrupt_handler
|
||||
|
||||
.macro INTERRUPT_NAME intno
|
||||
.quad __interrupt\intno
|
||||
.endm
|
||||
|
||||
.macro INTERRUPT_ERR intno
|
||||
__interrupt\intno:
|
||||
pushq $\intno
|
||||
jmp __interrupt_common
|
||||
.endm
|
||||
|
||||
.macro INTERRUPT_NOERR intno
|
||||
__interrupt\intno:
|
||||
pushq $0
|
||||
pushq $\intno
|
||||
jmp __interrupt_common
|
||||
.endm
|
||||
|
||||
.macro __pusha
|
||||
push %rax
|
||||
push %rbx
|
||||
push %rcx
|
||||
push %rdx
|
||||
push %rsi
|
||||
push %rdi
|
||||
push %rbp
|
||||
push %r8
|
||||
push %r9
|
||||
push %r10
|
||||
push %r11
|
||||
push %r12
|
||||
push %r13
|
||||
push %r14
|
||||
push %r15
|
||||
.endm
|
||||
|
||||
.macro __popa
|
||||
pop %r15
|
||||
pop %r14
|
||||
pop %r13
|
||||
pop %r12
|
||||
pop %r11
|
||||
pop %r10
|
||||
pop %r9
|
||||
pop %r8
|
||||
pop %rbp
|
||||
pop %rdi
|
||||
pop %rsi
|
||||
pop %rdx
|
||||
pop %rcx
|
||||
pop %rbx
|
||||
pop %rax
|
||||
.endm
|
||||
|
||||
__interrupt_common:
|
||||
cld
|
||||
__pusha
|
||||
|
||||
movq %rsp, %rdi
|
||||
call interrupt_handler
|
||||
movq %rax, %rsp
|
||||
|
||||
__popa
|
||||
add $16, %rsp
|
||||
iretq
|
||||
|
||||
.set i,0
|
||||
.rept 48
|
||||
.if i != 8 && i != 10 && i != 11 && i != 12 && i != 13 && i != 14 && i != 17 && i != 30
|
||||
INTERRUPT_NOERR %i
|
||||
.else
|
||||
INTERRUPT_ERR %i
|
||||
.endif
|
||||
.set i,i+1
|
||||
.endr
|
||||
|
||||
.align 8
|
||||
__interrupts_vector:
|
||||
.set i,0
|
||||
.rept 48
|
||||
INTERRUPT_NAME %i
|
||||
.set i,i+1
|
||||
.endr
|
||||
|
||||
idt_flush:
|
||||
lidt (%rdi)
|
||||
ret
|
37
src/kernel/archs/x86_64/idt.c
Normal file
37
src/kernel/archs/x86_64/idt.c
Normal file
|
@ -0,0 +1,37 @@
|
|||
#include <dbg/log.h>
|
||||
|
||||
#include "gdt.h"
|
||||
#include "idt.h"
|
||||
|
||||
static Idt idt;
|
||||
static IdtDescriptor idt_desc = {
|
||||
.size = sizeof(idt) - 1,
|
||||
.offset = (uintptr_t)&idt,
|
||||
};
|
||||
|
||||
static void idt_init_entry(IdtEntry *self, uint64_t base, uint8_t type)
|
||||
{
|
||||
self->offset_low = base & 0xFFFF;
|
||||
self->offset_mid = (base >> 16) & 0xFFFF;
|
||||
self->offset_high = (base >> 32) & 0xFFFFFFFF;
|
||||
self->ist = 0;
|
||||
self->selector = GDT_KERNEL_CODE * 8;
|
||||
self->type_attr = IDT_INT_PRESENT | type;
|
||||
self->zero = 0;
|
||||
}
|
||||
|
||||
uintptr_t idt_descriptor(void)
|
||||
{
|
||||
return (uintptr_t)&idt_desc;
|
||||
}
|
||||
|
||||
void idt_init(void)
|
||||
{
|
||||
for (size_t i = 0; i < IDT_ENTRY_COUNT; i++)
|
||||
{
|
||||
idt_init_entry(&idt.entries[i], __interrupts_vector[i], IDT_INT_GATE);
|
||||
}
|
||||
|
||||
idt_flush(idt_descriptor());
|
||||
log$("IDT lodaded");
|
||||
}
|
41
src/kernel/archs/x86_64/idt.h
Normal file
41
src/kernel/archs/x86_64/idt.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define IDT_ENTRY_COUNT (256)
|
||||
|
||||
enum
|
||||
{
|
||||
IDT_INT_PRESENT = (1 << 7),
|
||||
IDT_INT_GATE = (0xe),
|
||||
};
|
||||
|
||||
typedef struct [[gnu::packed]]
|
||||
{
|
||||
uint16_t size;
|
||||
uintptr_t offset;
|
||||
} IdtDescriptor;
|
||||
|
||||
typedef struct packed
|
||||
{
|
||||
uint16_t offset_low;
|
||||
uint16_t selector;
|
||||
uint8_t ist;
|
||||
uint8_t type_attr;
|
||||
uint16_t offset_mid;
|
||||
uint32_t offset_high;
|
||||
uint32_t zero;
|
||||
} IdtEntry;
|
||||
|
||||
typedef struct [[gnu::packed]]
|
||||
{
|
||||
IdtEntry entries[IDT_ENTRY_COUNT];
|
||||
} Idt;
|
||||
|
||||
void idt_init(void);
|
||||
|
||||
uintptr_t idt_descriptor(void);
|
||||
|
||||
extern uintptr_t __interrupts_vector[];
|
||||
|
||||
extern void idt_flush(uintptr_t);
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "e9.h"
|
||||
#include "gdt.h"
|
||||
#include "idt.h"
|
||||
|
||||
Stream hal_dbg_stream(void)
|
||||
{
|
||||
|
@ -15,5 +16,6 @@ Stream hal_dbg_stream(void)
|
|||
Res hal_setup(void)
|
||||
{
|
||||
gdt_init();
|
||||
idt_init();
|
||||
return ok$();
|
||||
}
|
31
src/kernel/archs/x86_64/regs.h
Normal file
31
src/kernel/archs/x86_64/regs.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct [[gnu::packed]] _HalRegs
|
||||
{
|
||||
uint64_t r15;
|
||||
uint64_t r14;
|
||||
uint64_t r13;
|
||||
uint64_t r12;
|
||||
uint64_t r11;
|
||||
uint64_t r10;
|
||||
uint64_t r9;
|
||||
uint64_t r8;
|
||||
uint64_t rbp;
|
||||
uint64_t rdi;
|
||||
uint64_t rsi;
|
||||
uint64_t rdx;
|
||||
uint64_t rcx;
|
||||
uint64_t rbx;
|
||||
uint64_t rax;
|
||||
|
||||
uint64_t intno;
|
||||
uint64_t err;
|
||||
|
||||
uint64_t rip;
|
||||
uint64_t cs;
|
||||
uint64_t rflags;
|
||||
uint64_t rsp;
|
||||
uint64_t ss;
|
||||
};
|
|
@ -5,6 +5,7 @@ _Noreturn int _start()
|
|||
{
|
||||
log$("Hello, world!");
|
||||
hal_setup();
|
||||
|
||||
for (;;)
|
||||
;
|
||||
}
|
Loading…
Reference in a new issue