From 29ebc06bee298c45b1aa071f4ccbe4a9384bb4d6 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 25 Mar 2019 16:43:09 +0200 Subject: [PATCH] [amd64] idt and exceptions --- conf/make/amd64.mk | 14 +++- conf/make/none.mk | 1 + src/arch/amd64/hw/exc.c | 15 ++++ src/arch/amd64/hw/idt.c | 123 +++++++++++++++++++++++++++++++ src/arch/amd64/hw/int_macros.inc | 37 ++++++++++ src/arch/amd64/hw/ints.S | 73 ++++++++++++++++++ src/arch/amd64/hw/ints.h | 3 + src/arch/amd64/hw/regs.c | 32 ++++++++ src/arch/amd64/hw/regs.h | 31 ++++++++ src/arch/amd64/kernel.c | 2 + 10 files changed, 327 insertions(+), 4 deletions(-) create mode 100644 src/arch/amd64/hw/exc.c create mode 100644 src/arch/amd64/hw/idt.c create mode 100644 src/arch/amd64/hw/int_macros.inc create mode 100644 src/arch/amd64/hw/ints.S create mode 100644 src/arch/amd64/hw/ints.h create mode 100644 src/arch/amd64/hw/regs.c create mode 100644 src/arch/amd64/hw/regs.h diff --git a/conf/make/amd64.mk b/conf/make/amd64.mk index 77f0119..10e17d5 100644 --- a/conf/make/amd64.mk +++ b/conf/make/amd64.mk @@ -6,24 +6,30 @@ OBJS+=$(O)/arch/amd64/kernel.o \ $(O)/arch/amd64/mm/mm.o \ $(O)/arch/amd64/hw/rs232.o \ $(O)/arch/amd64/hw/gdt.o \ - $(O)/arch/amd64/hw/gdt_s.o + $(O)/arch/amd64/hw/gdt_s.o \ + $(O)/arch/amd64/hw/idt.o \ + $(O)/arch/amd64/hw/ints.o \ + $(O)/arch/amd64/hw/exc.o \ + $(O)/arch/amd64/hw/regs.o kernel_OBJS=$(O)/arch/amd64/entry.o \ $(OBJS) kernel_LINKER=$(S)/arch/amd64/link.ld kernel_LDFLAGS=-nostdlib -T$(kernel_LINKER) -kernel_CFLAGS=-ffreestanding -I$(S) $(DEFINES) $(CFLAGS) +kernel_CFLAGS=-ffreestanding -I$(S) $(DEFINES) $(CFLAGS) -mcmodel=large DIRS+=$(O)/arch/amd64/mm \ $(O)/arch/amd64/hw +# add .inc includes for asm +HEADERS+=$(shell find $(S) -name "*.inc") $(O)/kernel.elf: $(kernel_OBJS) $(kernel_LINKER) @printf " LD\t%s\n" $@ @$(CROSSLD) $(kernel_LDFLAGS) -o $@ $(kernel_OBJS) -$(O)/%.o: $(S)/%.S +$(O)/%.o: $(S)/%.S $(HEADERS) @printf " AS\t%s\n" $@ @$(CROSSCC) $(kernel_CFLAGS) -c -o $@ $< -$(O)/%.o: $(S)/%.c +$(O)/%.o: $(S)/%.c $(HEADERS) @printf " CC\t%s\n" $@ @$(CROSSCC) $(kernel_CFLAGS) -c -o $@ $< diff --git a/conf/make/none.mk b/conf/make/none.mk index 70a8388..54a8ae0 100644 --- a/conf/make/none.mk +++ b/conf/make/none.mk @@ -3,6 +3,7 @@ HEADERS=$(shell find $(S) -name "*.h") CFLAGS+=-Wall \ -Wextra \ -Werror \ + -Wpedantic \ -Wno-unused-parameter DIRS+=$(O)/sys diff --git a/src/arch/amd64/hw/exc.c b/src/arch/amd64/hw/exc.c new file mode 100644 index 0000000..81ef992 --- /dev/null +++ b/src/arch/amd64/hw/exc.c @@ -0,0 +1,15 @@ +#include "ints.h" +#include "sys/debug.h" +#include "regs.h" + +int amd64_err_num; + +void amd64_exc_handler(amd64_ctx_regs_t *regs) { + kfatal("Unhandled exception #%d\n", amd64_err_num); + + amd64_ctx_dump(DEBUG_FATAL, regs); + + while (1) { + asm volatile ("cli; hlt"); + } +} diff --git a/src/arch/amd64/hw/idt.c b/src/arch/amd64/hw/idt.c new file mode 100644 index 0000000..cabaff7 --- /dev/null +++ b/src/arch/amd64/hw/idt.c @@ -0,0 +1,123 @@ +#include "ints.h" +#include "sys/mem.h" +#include +#include + +#define ignore(x) if (0) {x = x;} + +#define IDT_NENTR 256 + +#define IDT_FLG_TASK32 0x5 +#define IDT_FLG_INT16 0x6 +#define IDT_FLG_TRAP16 0x7 +#define IDT_FLG_INT32 0xE +#define IDT_FLG_TRAP32 0xF +#define IDT_FLG_SS (1 << 4) +#define IDT_FLG_R0 (0 << 5) +#define IDT_FLG_R1 (1 << 5) +#define IDT_FLG_R2 (2 << 5) +#define IDT_FLG_R3 (3 << 5) +#define IDT_FLG_P (1 << 7) + +extern void amd64_isr_0(); +extern void amd64_isr_1(); +extern void amd64_isr_2(); +extern void amd64_isr_3(); +extern void amd64_isr_4(); +extern void amd64_isr_5(); +extern void amd64_isr_6(); +extern void amd64_isr_7(); +extern void amd64_isr_8(); +extern void amd64_isr_9(); +extern void amd64_isr_10(); +extern void amd64_isr_11(); +extern void amd64_isr_12(); +extern void amd64_isr_13(); +extern void amd64_isr_14(); +extern void amd64_isr_15(); +extern void amd64_isr_16(); +extern void amd64_isr_17(); +extern void amd64_isr_18(); +extern void amd64_isr_19(); +extern void amd64_isr_20(); +extern void amd64_isr_21(); +extern void amd64_isr_22(); +extern void amd64_isr_23(); +extern void amd64_isr_24(); +extern void amd64_isr_25(); +extern void amd64_isr_26(); +extern void amd64_isr_27(); +extern void amd64_isr_28(); +extern void amd64_isr_29(); +extern void amd64_isr_30(); +extern void amd64_isr_31(); + +typedef struct { + uint16_t base_lo; + uint16_t selector; + uint8_t zero; + uint8_t flags; + uint16_t base_hi; + uint32_t base_ex; + uint32_t zero1; +} amd64_idt_entry_t; + +typedef struct { + uint16_t size; + uintptr_t offset; +} __attribute__((packed)) amd64_idt_ptr_t; + +static amd64_idt_entry_t idt[IDT_NENTR]; +static amd64_idt_ptr_t idtr; + +void amd64_idt_set(int idx, uintptr_t base, uint16_t selector, uint8_t flags) { + idt[idx].base_lo = base & 0xFFFF; + idt[idx].base_hi = (base >> 16) & 0xFFFF; + idt[idx].base_ex = (base >> 32) & 0xFFFFFFFF; + idt[idx].selector = selector; + idt[idx].flags = flags; + idt[idx].zero = 0; +} + +void amd64_idt_init(void) { + idtr.offset = (uintptr_t) idt; + idtr.size = sizeof(idt) - 1; + + memset(idt, 0, sizeof(idt)); + + // Exceptions + amd64_idt_set(0 , (uintptr_t) amd64_isr_0 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(1 , (uintptr_t) amd64_isr_1 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(2 , (uintptr_t) amd64_isr_2 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(3 , (uintptr_t) amd64_isr_3 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(4 , (uintptr_t) amd64_isr_4 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(5 , (uintptr_t) amd64_isr_5 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(6 , (uintptr_t) amd64_isr_6 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(7 , (uintptr_t) amd64_isr_7 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(8 , (uintptr_t) amd64_isr_8 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(9 , (uintptr_t) amd64_isr_9 , 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(10, (uintptr_t) amd64_isr_10, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(11, (uintptr_t) amd64_isr_11, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(12, (uintptr_t) amd64_isr_12, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(13, (uintptr_t) amd64_isr_13, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(14, (uintptr_t) amd64_isr_14, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(15, (uintptr_t) amd64_isr_15, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(16, (uintptr_t) amd64_isr_16, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(17, (uintptr_t) amd64_isr_17, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(18, (uintptr_t) amd64_isr_18, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(19, (uintptr_t) amd64_isr_19, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(20, (uintptr_t) amd64_isr_20, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(21, (uintptr_t) amd64_isr_21, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(22, (uintptr_t) amd64_isr_22, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(23, (uintptr_t) amd64_isr_23, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(24, (uintptr_t) amd64_isr_24, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(25, (uintptr_t) amd64_isr_25, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(26, (uintptr_t) amd64_isr_26, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(27, (uintptr_t) amd64_isr_27, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(28, (uintptr_t) amd64_isr_28, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(29, (uintptr_t) amd64_isr_29, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(30, (uintptr_t) amd64_isr_30, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + amd64_idt_set(31, (uintptr_t) amd64_isr_31, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32); + + asm volatile ("lea idtr(%%rip), %%rax; lidt (%%rax)":::"memory"); +} diff --git a/src/arch/amd64/hw/int_macros.inc b/src/arch/amd64/hw/int_macros.inc new file mode 100644 index 0000000..b8121e8 --- /dev/null +++ b/src/arch/amd64/hw/int_macros.inc @@ -0,0 +1,37 @@ +// vi:syntax=asm + +.macro __int_push_ctx + // pushal for amd64 world + pushq %rax + pushq %rcx + pushq %rdx + pushq %rbx + pushq %rsp + pushq %rbp + pushq %rsi + pushq %rdi + + // r8-r15 + pushq %r8 + pushq %r9 + pushq %r10 + pushq %r11 + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + + // cr3 + mov %cr3, %rax + pushq %rax + + // segments + mov %gs, %rax + pushq %rax + mov %fs, %rax + pushq %rax + mov %es, %rax + pushq %rax + mov %ds, %rax + pushq %rax +.endm diff --git a/src/arch/amd64/hw/ints.S b/src/arch/amd64/hw/ints.S new file mode 100644 index 0000000..adadd4e --- /dev/null +++ b/src/arch/amd64/hw/ints.S @@ -0,0 +1,73 @@ +#include "int_macros.inc" +.section .text +.extern amd64_err_num + +__isr_generic: + cli + + // TODO: preserve error codes + pushq %rax + mov 8(%rsp), %rax + mov %rax, amd64_err_num(%rip) + popq %rax + add $16, %rsp + + __int_push_ctx + + movq %rsp, %rdi + call amd64_exc_handler + + // TODO: allow handling and returning from an exception ISR +1: + hlt + jmp 1b + +// ISR with error code +.macro __isr_yerr n +.global amd64_isr_\n +amd64_isr_\n: + pushq $\n + jmp __isr_generic +.endm + +// ISR with no error code +.macro __isr_nerr n +.global amd64_isr_\n +amd64_isr_\n: + pushq $0 + pushq $\n + jmp __isr_generic +.endm + +__isr_nerr 0 +__isr_nerr 1 +__isr_nerr 2 +__isr_nerr 3 +__isr_nerr 4 +__isr_nerr 5 +__isr_nerr 6 +__isr_nerr 7 +__isr_yerr 8 +__isr_nerr 9 +__isr_yerr 10 +__isr_yerr 11 +__isr_yerr 12 +__isr_yerr 13 +__isr_yerr 14 +__isr_nerr 15 +__isr_nerr 16 +__isr_yerr 17 +__isr_nerr 18 +__isr_nerr 19 +__isr_nerr 20 +__isr_nerr 21 +__isr_nerr 22 +__isr_nerr 23 +__isr_nerr 24 +__isr_nerr 25 +__isr_nerr 26 +__isr_nerr 27 +__isr_nerr 28 +__isr_nerr 29 +__isr_yerr 30 +__isr_nerr 31 diff --git a/src/arch/amd64/hw/ints.h b/src/arch/amd64/hw/ints.h new file mode 100644 index 0000000..b580ca3 --- /dev/null +++ b/src/arch/amd64/hw/ints.h @@ -0,0 +1,3 @@ +#pragma once + +void amd64_idt_init(void); diff --git a/src/arch/amd64/hw/regs.c b/src/arch/amd64/hw/regs.c new file mode 100644 index 0000000..ec41a13 --- /dev/null +++ b/src/arch/amd64/hw/regs.c @@ -0,0 +1,32 @@ +#include "regs.h" +#include "sys/debug.h" + +void amd64_ctx_dump(int level, const amd64_ctx_regs_t *regs) { + kprint(level, "rax = %p (%ld)\n", regs->gp.rax, regs->gp.rax); + kprint(level, "rcx = %p (%ld)\n", regs->gp.rcx, regs->gp.rcx); + kprint(level, "rdx = %p (%ld)\n", regs->gp.rdx, regs->gp.rdx); + kprint(level, "rbx = %p (%ld)\n", regs->gp.rbx, regs->gp.rbx); + + kprint(level, "r8 = %p (%ld)\n", regs->gp.r8, regs->gp.r8); + kprint(level, "r9 = %p (%ld)\n", regs->gp.r9, regs->gp.r9); + kprint(level, "r10 = %p (%ld)\n", regs->gp.r10, regs->gp.r10); + kprint(level, "r11 = %p (%ld)\n", regs->gp.r11, regs->gp.r11); + kprint(level, "r12 = %p (%ld)\n", regs->gp.r12, regs->gp.r12); + kprint(level, "r13 = %p (%ld)\n", regs->gp.r13, regs->gp.r13); + kprint(level, "r14 = %p (%ld)\n", regs->gp.r14, regs->gp.r14); + kprint(level, "r15 = %p (%ld)\n", regs->gp.r15, regs->gp.r15); + + if (regs->iret.cs == 0x08) { + // Print stack pointer before the exception occurred + kprint(level, "rsp = %p\n", regs->gp.rsp + sizeof(amd64_ctx_regs_t)); + } + kprint(level, "rbp = %p\n", regs->gp.rbp); + kprint(level, "rsi = %p\n", regs->gp.rsi); + kprint(level, "rdi = %p\n", regs->gp.rdi); + + kprint(level, "pc: %02x:%p\n", regs->iret.cs, regs->iret.rip); + + if (regs->iret.cs != 0x08) { + kprint(level, "stack: %02x:%p\n", regs->iret.ss, regs->iret.rsp); + } +} diff --git a/src/arch/amd64/hw/regs.h b/src/arch/amd64/hw/regs.h new file mode 100644 index 0000000..52ff78c --- /dev/null +++ b/src/arch/amd64/hw/regs.h @@ -0,0 +1,31 @@ +#pragma once +#include + +typedef struct { + uint64_t rip; + uint64_t cs; + uint64_t rflags; + uint64_t rsp; + uint64_t ss; +} amd64_iret_regs_t; + +typedef struct { + uint64_t ds; + uint64_t es; + uint64_t fs; + uint64_t gs; +} amd64_seg_regs_t; + +typedef struct { + uint64_t r15, r14, r13, r12, r11, r10, r9, r8; + uint64_t rdi, rsi, rbp, rsp, rbx, rdx, rcx, rax; +} amd64_gp_regs_t; + +typedef struct { + amd64_seg_regs_t segs; + uint64_t cr3; + amd64_gp_regs_t gp; + amd64_iret_regs_t iret; +} amd64_ctx_regs_t; + +void amd64_ctx_dump(int level, const amd64_ctx_regs_t *regs); diff --git a/src/arch/amd64/kernel.c b/src/arch/amd64/kernel.c index 7e0277a..e4eb634 100644 --- a/src/arch/amd64/kernel.c +++ b/src/arch/amd64/kernel.c @@ -1,6 +1,7 @@ #include "sys/mm.h" #include "sys/debug.h" #include "arch/amd64/hw/gdt.h" +#include "arch/amd64/hw/ints.h" void kernel_main(void) { kdebug("Booting\n"); @@ -8,4 +9,5 @@ void kernel_main(void) { // Memory management amd64_mm_init(); amd64_gdt_init(); + amd64_idt_init(); }