feat/kernel: Added IDT
This commit is contained in:
parent
248879c099
commit
af7599a266
15 changed files with 412 additions and 19 deletions
9
.vscode/settings.json
vendored
9
.vscode/settings.json
vendored
|
@ -1,10 +1,7 @@
|
|||
{
|
||||
"files.associations": {
|
||||
"stdnoreturn.h": "c",
|
||||
"serial.h": "c",
|
||||
"io.h": "c",
|
||||
"kprintf.h": "c",
|
||||
"log.h": "c",
|
||||
"cpu.h": "c"
|
||||
"cstdio": "c",
|
||||
"stdarg.h": "c",
|
||||
"idt.h": "c"
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
MAKEFLAGS += -rR
|
||||
.SUFFIXES:
|
||||
|
||||
QEMUFLAGS := -m 2G -serial stdio
|
||||
QEMUFLAGS := -m 2G -serial stdio -display none
|
||||
IMAGE_NAME := release/emk
|
||||
|
||||
HOST_CC := cc
|
||||
|
|
|
@ -12,15 +12,30 @@ CC := gcc
|
|||
AS := gcc
|
||||
NASM := nasm
|
||||
|
||||
CFLAGS := -g -O2 -pipe -Wall -Wextra -Werror -std=gnu11 -ffreestanding \
|
||||
# Build mode configuration
|
||||
BUILD_MODE ?= dev
|
||||
ifeq ($(BUILD_MODE),release)
|
||||
CFLAGS := -Os -pipe -Wall -Wextra -Werror -std=gnu11 -ffreestanding \
|
||||
-fno-stack-protector -fno-stack-check -fno-PIC \
|
||||
-ffunction-sections -fdata-sections -m64 -march=x86-64 \
|
||||
-mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone \
|
||||
-mcmodel=kernel -fno-unwind-tables -fno-asynchronous-unwind-tables \
|
||||
-s -Wno-unused-variable
|
||||
NASMFLAGS :=
|
||||
LDFLAGS := -nostdlib -static -z max-page-size=0x1000 -Wl,--gc-sections \
|
||||
-T linker.ld -Wl,-m,elf_x86_64 -Wl,--strip-all
|
||||
else
|
||||
CFLAGS := -g -O2 -pipe -Wall -Wextra -Werror -std=gnu11 -ffreestanding \
|
||||
-fno-stack-protector -fno-stack-check -fno-PIC \
|
||||
-ffunction-sections -fdata-sections -m64 -march=x86-64 \
|
||||
-mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone \
|
||||
-mcmodel=kernel -Wno-unused-variable
|
||||
CPPFLAGS := -I../external -I$(SRCDIR) -MMD -MP -DLIMINE_API_REVISION=3
|
||||
NASMFLAGS := -F dwarf -g
|
||||
LDFLAGS := -nostdlib -static -z max-page-size=0x1000 -Wl,--gc-sections \
|
||||
NASMFLAGS := -F dwarf -g
|
||||
LDFLAGS := -nostdlib -static -z max-page-size=0x1000 -Wl,--gc-sections \
|
||||
-T linker.ld -Wl,-m,elf_x86_64
|
||||
endif
|
||||
|
||||
CPPFLAGS := -I../external -I$(SRCDIR) -MMD -MP -DLIMINE_API_REVISION=3
|
||||
|
||||
SRCS := $(shell find $(SRCDIR) -type f \( -name '*.c' -o -name '*.S' -o -name '*.asm' \))
|
||||
OBJS := $(patsubst %.c,$(OBJDIR)/%.o,$(filter %.c,$(SRCS))) \
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* EMK 1.0 Copyright (c) 2025 Piraterna */
|
||||
#include <arch/gdt.h>
|
||||
|
||||
gdt_entry_t gdt[5];
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* EMK 1.0 Copyright (c) 2025 Piraterna */
|
||||
#ifndef GDT_H
|
||||
#define GDT_H
|
||||
|
||||
|
|
94
kernel/src/arch/idt-stub.S
Normal file
94
kernel/src/arch/idt-stub.S
Normal file
|
@ -0,0 +1,94 @@
|
|||
.globl real_handlers
|
||||
.extern real_handlers
|
||||
|
||||
isr_handler_stub:
|
||||
pushq %rax
|
||||
pushq %rbx
|
||||
pushq %rcx
|
||||
pushq %rdx
|
||||
pushq %rbp
|
||||
pushq %rdi
|
||||
pushq %rsi
|
||||
pushq %r8
|
||||
pushq %r9
|
||||
pushq %r10
|
||||
pushq %r11
|
||||
pushq %r12
|
||||
pushq %r13
|
||||
pushq %r14
|
||||
pushq %r15
|
||||
|
||||
movq %cr0, %rax
|
||||
pushq %rax
|
||||
movq %cr2, %rax
|
||||
pushq %rax
|
||||
movq %cr3, %rax
|
||||
pushq %rax
|
||||
movq %cr4, %rax
|
||||
pushq %rax
|
||||
|
||||
movq %ds, %rax
|
||||
pushq %rax
|
||||
movq %es, %rax
|
||||
pushq %rax
|
||||
|
||||
cld
|
||||
|
||||
movq %rsp, %rdi
|
||||
movq 168(%rsp), %rbx
|
||||
shlq $3, %rbx
|
||||
leaq real_handlers(%rip), %rax
|
||||
addq %rbx, %rax
|
||||
callq *(%rax)
|
||||
|
||||
addq $48, %rsp
|
||||
popq %r15
|
||||
popq %r14
|
||||
popq %r13
|
||||
popq %r12
|
||||
popq %r11
|
||||
popq %r10
|
||||
popq %r9
|
||||
popq %r8
|
||||
popq %rsi
|
||||
popq %rdi
|
||||
popq %rbp
|
||||
popq %rdx
|
||||
popq %rcx
|
||||
popq %rbx
|
||||
popq %rax
|
||||
addq $16, %rsp
|
||||
|
||||
iretq
|
||||
|
||||
.macro ISR index
|
||||
.global _isr\index
|
||||
.type _isr\index, @function
|
||||
_isr\index:
|
||||
.if 0x\index != 8 && 0x\index != 10 && 0x\index != 11 && 0x\index != 12 && 0x\index != 13 && 0x\index != 14 && 0x\index != 17 && 0x\index != 30
|
||||
pushq $0
|
||||
.endif
|
||||
pushq $0x\index
|
||||
jmp isr_handler_stub
|
||||
.endm
|
||||
|
||||
.macro ISRADDR index
|
||||
.quad _isr\index
|
||||
.endm
|
||||
|
||||
.irpc i, 0123456789abcdef
|
||||
.irpc j, 0123456789abcdef
|
||||
ISR \i\j
|
||||
.endr
|
||||
.endr
|
||||
|
||||
.section .data
|
||||
|
||||
.global stubs
|
||||
.align 8
|
||||
stubs:
|
||||
.irpc i, 0123456789abcdef
|
||||
.irpc j, 0123456789abcdef
|
||||
ISRADDR \i\j
|
||||
.endr
|
||||
.endr
|
63
kernel/src/arch/idt.c
Normal file
63
kernel/src/arch/idt.c
Normal file
|
@ -0,0 +1,63 @@
|
|||
#include <arch/idt.h>
|
||||
#include <lib/string.h>
|
||||
#include <stdarg.h>
|
||||
#include <arch/cpu.h>
|
||||
#include <util/log.h>
|
||||
#include <sys/kpanic.h>
|
||||
|
||||
struct idt_entry __attribute__((aligned(16))) idt_descriptor[256] = {0};
|
||||
idt_intr_handler real_handlers[256] = {0};
|
||||
extern uint64_t stubs[];
|
||||
|
||||
struct __attribute__((packed)) idt_ptr
|
||||
{
|
||||
uint16_t limit;
|
||||
uint64_t base;
|
||||
};
|
||||
|
||||
struct idt_ptr idt_ptr = {sizeof(idt_descriptor) - 1, (uint64_t)&idt_descriptor};
|
||||
|
||||
void idt_default_interrupt_handler(struct register_ctx *ctx)
|
||||
{
|
||||
kpanic(ctx, NULL);
|
||||
}
|
||||
|
||||
#define SET_GATE(interrupt, base, flags) \
|
||||
do \
|
||||
{ \
|
||||
idt_descriptor[(interrupt)].off_low = (base) & 0xFFFF; \
|
||||
idt_descriptor[(interrupt)].sel = 0x8; \
|
||||
idt_descriptor[(interrupt)].ist = 0; \
|
||||
idt_descriptor[(interrupt)].attr = (flags); \
|
||||
idt_descriptor[(interrupt)].off_mid = ((base) >> 16) & 0xFFFF; \
|
||||
idt_descriptor[(interrupt)].off_high = ((base) >> 32) & 0xFFFFFFFF; \
|
||||
idt_descriptor[(interrupt)].zero = 0; \
|
||||
} while (0)
|
||||
|
||||
void idt_init()
|
||||
{
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
SET_GATE(i, stubs[i], IDT_TRAP_GATE);
|
||||
real_handlers[i] = idt_default_interrupt_handler;
|
||||
}
|
||||
|
||||
for (int i = 32; i < 256; i++)
|
||||
{
|
||||
SET_GATE(i, stubs[i], IDT_INTERRUPT_GATE);
|
||||
}
|
||||
|
||||
__asm__ volatile(
|
||||
"lidt %0"
|
||||
: : "m"(idt_ptr) : "memory");
|
||||
}
|
||||
|
||||
int idt_register_handler(size_t vector, idt_intr_handler handler)
|
||||
{
|
||||
if (real_handlers[vector] != idt_default_interrupt_handler)
|
||||
{
|
||||
real_handlers[vector] = handler;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
37
kernel/src/arch/idt.h
Normal file
37
kernel/src/arch/idt.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/* EMK 1.0 Copyright (c) 2025 Piraterna */
|
||||
#ifndef IDT_H
|
||||
#define IDT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
struct __attribute__((packed)) register_ctx
|
||||
{
|
||||
uint64_t es, ds;
|
||||
uint64_t cr4, cr3, cr2, cr0;
|
||||
uint64_t r15, r14, r13, r12, r11, r10, r9, r8, rsi, rdi, rbp, rdx, rcx, rbx, rax;
|
||||
uint64_t vector, err;
|
||||
uint64_t rip, cs, rflags, rsp, ss;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) idt_entry
|
||||
{
|
||||
uint16_t off_low;
|
||||
uint16_t sel;
|
||||
uint8_t ist;
|
||||
uint8_t attr;
|
||||
uint16_t off_mid;
|
||||
uint32_t off_high;
|
||||
uint32_t zero;
|
||||
};
|
||||
|
||||
typedef void (*idt_intr_handler)(struct register_ctx *ctx);
|
||||
#define IDT_INTERRUPT_GATE (0x8E)
|
||||
#define IDT_TRAP_GATE (0x8F)
|
||||
#define IDT_IRQ_BASE (0x20)
|
||||
|
||||
void idt_init();
|
||||
int idt_register_handler(size_t vector, idt_intr_handler handler);
|
||||
void idt_default_interrupt_handler(struct register_ctx *ctx);
|
||||
|
||||
#endif // IDT_H
|
|
@ -6,6 +6,7 @@
|
|||
#include <util/kprintf.h>
|
||||
#include <util/log.h>
|
||||
#include <arch/gdt.h>
|
||||
#include <arch/idt.h>
|
||||
|
||||
__attribute__((used, section(".limine_requests"))) static volatile LIMINE_BASE_REVISION(3);
|
||||
__attribute__((used, section(".limine_requests_start"))) static volatile LIMINE_REQUESTS_START_MARKER;
|
||||
|
@ -21,11 +22,15 @@ void emk_entry(void)
|
|||
|
||||
if (!LIMINE_BASE_REVISION_SUPPORTED)
|
||||
{
|
||||
early("ERROR: Limine base revision is not supported\n");
|
||||
log_early("ERROR: Limine base revision is not supported\n");
|
||||
hcf();
|
||||
}
|
||||
|
||||
gdt_init();
|
||||
early("Initialized GDT");
|
||||
log_early("Initialized GDT");
|
||||
idt_init();
|
||||
log_early("Initialized IDT");
|
||||
__asm__ volatile("int $0x01");
|
||||
|
||||
hlt();
|
||||
}
|
140
kernel/src/sys/kpanic.c
Normal file
140
kernel/src/sys/kpanic.c
Normal file
|
@ -0,0 +1,140 @@
|
|||
#include <sys/kpanic.h>
|
||||
#include <util/log.h>
|
||||
#include <stdarg.h>
|
||||
#include <util/kprintf.h>
|
||||
#include <lib/string.h>
|
||||
#include <arch/cpu.h>
|
||||
|
||||
static const char *strings[32] = {
|
||||
"Division by Zero",
|
||||
"Debug",
|
||||
"Non-Maskable-Interrupt",
|
||||
"Breakpoint",
|
||||
"Overflow",
|
||||
"Bound Range Exceeded",
|
||||
"Invalid opcode",
|
||||
"Device (FPU) not available",
|
||||
"Double Fault",
|
||||
"RESERVED VECTOR",
|
||||
"Invalid TSS",
|
||||
"Segment not present",
|
||||
"Stack Segment Fault",
|
||||
"General Protection Fault",
|
||||
"Page Fault",
|
||||
"RESERVED VECTOR",
|
||||
"x87 FP Exception",
|
||||
"Alignment Check",
|
||||
"Machine Check (Internal Error)",
|
||||
"SIMD FP Exception",
|
||||
"Virtualization Exception",
|
||||
"Control Protection Exception",
|
||||
"RESERVED VECTOR",
|
||||
"RESERVED VECTOR",
|
||||
"RESERVED VECTOR",
|
||||
"RESERVED VECTOR",
|
||||
"RESERVED VECTOR",
|
||||
"RESERVED VECTOR",
|
||||
"Hypervisor Injection Exception",
|
||||
"VMM Communication Exception",
|
||||
"Security Exception",
|
||||
"RESERVED VECTOR"};
|
||||
|
||||
static void capture_regs(struct register_ctx *context)
|
||||
{
|
||||
__asm__ volatile(
|
||||
"movq %%rax, %0\n\t"
|
||||
"movq %%rbx, %1\n\t"
|
||||
"movq %%rcx, %2\n\t"
|
||||
"movq %%rdx, %3\n\t"
|
||||
"movq %%rsi, %4\n\t"
|
||||
"movq %%rdi, %5\n\t"
|
||||
"movq %%rbp, %6\n\t"
|
||||
"movq %%r8, %7\n\t"
|
||||
"movq %%r9, %8\n\t"
|
||||
"movq %%r10, %9\n\t"
|
||||
"movq %%r11, %10\n\t"
|
||||
"movq %%r12, %11\n\t"
|
||||
"movq %%r13, %12\n\t"
|
||||
"movq %%r14, %13\n\t"
|
||||
"movq %%r15, %14\n\t"
|
||||
: "=m"(context->rax), "=m"(context->rbx), "=m"(context->rcx), "=m"(context->rdx),
|
||||
"=m"(context->rsi), "=m"(context->rdi), "=m"(context->rbp), "=m"(context->r9),
|
||||
"=m"(context->r9), "=m"(context->r10), "=m"(context->r11), "=m"(context->r12),
|
||||
"=m"(context->r13), "=m"(context->r14), "=m"(context->r15)
|
||||
:
|
||||
: "memory");
|
||||
|
||||
__asm__ volatile(
|
||||
"movq %%cs, %0\n\t"
|
||||
"movq %%ss, %1\n\t"
|
||||
"movq %%es, %2\n\t"
|
||||
"movq %%ds, %3\n\t"
|
||||
"movq %%cr0, %4\n\t"
|
||||
"movq %%cr2, %5\n\t"
|
||||
"movq %%cr3, %6\n\t"
|
||||
"movq %%cr4, %7\n\t"
|
||||
: "=r"(context->cs), "=r"(context->ss), "=r"(context->es), "=r"(context->ds),
|
||||
"=r"(context->cr0), "=r"(context->cr2), "=r"(context->cr3), "=r"(context->cr4)
|
||||
:
|
||||
: "memory");
|
||||
|
||||
__asm__ volatile(
|
||||
"movq %%rsp, %0\n\t"
|
||||
"pushfq\n\t"
|
||||
"popq %1\n\t"
|
||||
: "=r"(context->rsp), "=r"(context->rflags)
|
||||
:
|
||||
: "memory");
|
||||
|
||||
context->rip = (uint64_t)__builtin_return_address(0);
|
||||
}
|
||||
|
||||
void kpanic(struct register_ctx *ctx, const char *fmt, ...)
|
||||
{
|
||||
struct register_ctx regs;
|
||||
|
||||
if (ctx == NULL)
|
||||
{
|
||||
capture_regs(®s);
|
||||
regs.err = 0xDEADBEEF;
|
||||
regs.vector = 0x0;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(®s, ctx, sizeof(struct register_ctx));
|
||||
}
|
||||
|
||||
char buf[1024];
|
||||
|
||||
if (fmt)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (regs.vector >= sizeof(strings) / sizeof(strings[0]))
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "Unknown panic vector: %d", regs.vector);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "%s", strings[regs.vector]);
|
||||
}
|
||||
}
|
||||
|
||||
log_panic("=== Kernel panic: '%s' @ 0x%.16llx ===", buf, regs.rip);
|
||||
log_panic("Registers:");
|
||||
log_panic(" rax: 0x%.16llx rbx: 0x%.16llx rcx: 0x%.16llx rdx: 0x%.16llx", regs.rax, regs.rbx, regs.rcx, regs.rdx);
|
||||
log_panic(" rsi: 0x%.16llx rdi: 0x%.16llx rbp: 0x%.16llx rsp: 0x%.16llx", regs.rsi, regs.rdi, regs.rbp, regs.rsp);
|
||||
log_panic(" r8 : 0x%.16llx r9 : 0x%.16llx r10: 0x%.16llx r11: 0x%.16llx", regs.r8, regs.r9, regs.r10, regs.r11);
|
||||
log_panic(" r12: 0x%.16llx r13: 0x%.16llx r14: 0x%.16llx r15: 0x%.16llx", regs.r12, regs.r13, regs.r14, regs.r15);
|
||||
log_panic(" rip: 0x%.16llx rflags: 0x%.16llx", regs.rip, regs.rflags);
|
||||
log_panic(" cs : 0x%.16llx ss: 0x%.16llx ds: 0x%.16llx es: 0x%.16llx", regs.cs, regs.ss, regs.ds, regs.es);
|
||||
log_panic(" cr0: 0x%.16llx cr2: 0x%.16llx cr3: 0x%.16llx cr4: 0x%.16llx", regs.cr0, regs.cr2, regs.cr3, regs.cr4);
|
||||
log_panic(" err: 0x%.16llx vector: 0x%.16llx", regs.err, regs.vector);
|
||||
|
||||
hcf();
|
||||
}
|
8
kernel/src/sys/kpanic.h
Normal file
8
kernel/src/sys/kpanic.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#ifndef KPANIC_H
|
||||
#define KPANIC_H
|
||||
|
||||
#include <arch/idt.h>
|
||||
|
||||
void kpanic(struct register_ctx *ctx, const char *fmt, ...);
|
||||
|
||||
#endif // KPANIC_H
|
|
@ -1,3 +1,4 @@
|
|||
/* EMK 1.0 Copyright (c) 2025 Piraterna */
|
||||
#include <dev/serial.h>
|
||||
#include <util/kprintf.h>
|
||||
|
||||
|
@ -26,3 +27,24 @@ int kprintf(const char *fmt, ...)
|
|||
va_end(args);
|
||||
return length;
|
||||
}
|
||||
|
||||
int snprintf(char *buf, size_t size, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int length = vsnprintf(buf, size, fmt, args);
|
||||
va_end(args);
|
||||
return length;
|
||||
}
|
||||
|
||||
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
|
||||
{
|
||||
int length = npf_vsnprintf(buf, size, fmt, args);
|
||||
|
||||
if (length >= (int)size)
|
||||
{
|
||||
buf[size - 1] = '\0';
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
|
@ -1,7 +1,15 @@
|
|||
/* EMK 1.0 Copyright (c) 2025 Piraterna */
|
||||
#ifndef KPRINTF_H
|
||||
#define KPRINTF_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/* Minimal kprintf using nanoprintf, see external/nanoprintf.h */
|
||||
int kprintf(const char *fmt, ...);
|
||||
|
||||
/* Careful with these */
|
||||
int snprintf(char *buf, size_t size, const char *fmt, ...);
|
||||
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
|
||||
|
||||
#endif // KPRINTF_H
|
|
@ -1,8 +1,10 @@
|
|||
/* EMK 1.0 Copyright (c) 2025 Piraterna */
|
||||
#ifndef LOG_H
|
||||
#define LOG_H
|
||||
|
||||
#include <util/kprintf.h>
|
||||
|
||||
#define early(fmt, ...) kprintf("early: " fmt "\n", ##__VA_ARGS__)
|
||||
#define log_early(fmt, ...) kprintf("early: " fmt "\n", ##__VA_ARGS__)
|
||||
#define log_panic(fmt, ...) kprintf("panic: " fmt "\n", ##__VA_ARGS__)
|
||||
|
||||
#endif // LOG_H
|
|
@ -1,4 +1,4 @@
|
|||
timeout: 3
|
||||
timeout: 0
|
||||
|
||||
/EMK
|
||||
protocol: limine
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue