1
0
Fork 0

feat/kernel: Added IDT

This commit is contained in:
Kevin Alavik 2025-05-14 14:23:13 +02:00
parent 248879c099
commit af7599a266
Signed by: cmpsb
GPG key ID: 10D1CC0526FDC6D7
15 changed files with 412 additions and 19 deletions

View file

@ -1,10 +1,7 @@
{ {
"files.associations": { "files.associations": {
"stdnoreturn.h": "c", "cstdio": "c",
"serial.h": "c", "stdarg.h": "c",
"io.h": "c", "idt.h": "c"
"kprintf.h": "c",
"log.h": "c",
"cpu.h": "c"
} }
} }

View file

@ -2,7 +2,7 @@
MAKEFLAGS += -rR MAKEFLAGS += -rR
.SUFFIXES: .SUFFIXES:
QEMUFLAGS := -m 2G -serial stdio QEMUFLAGS := -m 2G -serial stdio -display none
IMAGE_NAME := release/emk IMAGE_NAME := release/emk
HOST_CC := cc HOST_CC := cc

View file

@ -12,15 +12,30 @@ CC := gcc
AS := gcc AS := gcc
NASM := nasm NASM := nasm
CFLAGS := -g -O2 -pipe -Wall -Wextra -Werror -std=gnu11 -ffreestanding \ # Build mode configuration
-fno-stack-protector -fno-stack-check -fno-PIC \ BUILD_MODE ?= dev
-ffunction-sections -fdata-sections -m64 -march=x86-64 \ ifeq ($(BUILD_MODE),release)
-mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone \ CFLAGS := -Os -pipe -Wall -Wextra -Werror -std=gnu11 -ffreestanding \
-mcmodel=kernel -Wno-unused-variable -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
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 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 \
-T linker.ld -Wl,-m,elf_x86_64
SRCS := $(shell find $(SRCDIR) -type f \( -name '*.c' -o -name '*.S' -o -name '*.asm' \)) SRCS := $(shell find $(SRCDIR) -type f \( -name '*.c' -o -name '*.S' -o -name '*.asm' \))
OBJS := $(patsubst %.c,$(OBJDIR)/%.o,$(filter %.c,$(SRCS))) \ OBJS := $(patsubst %.c,$(OBJDIR)/%.o,$(filter %.c,$(SRCS))) \

View file

@ -1,3 +1,4 @@
/* EMK 1.0 Copyright (c) 2025 Piraterna */
#include <arch/gdt.h> #include <arch/gdt.h>
gdt_entry_t gdt[5]; gdt_entry_t gdt[5];

View file

@ -1,3 +1,4 @@
/* EMK 1.0 Copyright (c) 2025 Piraterna */
#ifndef GDT_H #ifndef GDT_H
#define GDT_H #define GDT_H

View 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
View 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
View 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

View file

@ -6,6 +6,7 @@
#include <util/kprintf.h> #include <util/kprintf.h>
#include <util/log.h> #include <util/log.h>
#include <arch/gdt.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"))) static volatile LIMINE_BASE_REVISION(3);
__attribute__((used, section(".limine_requests_start"))) static volatile LIMINE_REQUESTS_START_MARKER; __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) 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(); hcf();
} }
gdt_init(); gdt_init();
early("Initialized GDT"); log_early("Initialized GDT");
idt_init();
log_early("Initialized IDT");
__asm__ volatile("int $0x01");
hlt(); hlt();
} }

140
kernel/src/sys/kpanic.c Normal file
View 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(&regs);
regs.err = 0xDEADBEEF;
regs.vector = 0x0;
}
else
{
memcpy(&regs, 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
View 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

View file

@ -1,3 +1,4 @@
/* EMK 1.0 Copyright (c) 2025 Piraterna */
#include <dev/serial.h> #include <dev/serial.h>
#include <util/kprintf.h> #include <util/kprintf.h>
@ -24,5 +25,26 @@ int kprintf(const char *fmt, ...)
} }
va_end(args); 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; return length;
} }

View file

@ -1,7 +1,15 @@
/* EMK 1.0 Copyright (c) 2025 Piraterna */
#ifndef KPRINTF_H #ifndef KPRINTF_H
#define KPRINTF_H #define KPRINTF_H
#include <stddef.h>
#include <stdarg.h>
/* Minimal kprintf using nanoprintf, see external/nanoprintf.h */ /* Minimal kprintf using nanoprintf, see external/nanoprintf.h */
int kprintf(const char *fmt, ...); 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 #endif // KPRINTF_H

View file

@ -1,8 +1,10 @@
/* EMK 1.0 Copyright (c) 2025 Piraterna */
#ifndef LOG_H #ifndef LOG_H
#define LOG_H #define LOG_H
#include <util/kprintf.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 #endif // LOG_H

View file

@ -1,4 +1,4 @@
timeout: 3 timeout: 0
/EMK /EMK
protocol: limine protocol: limine