diff --git a/.gdbinit b/.gdbinit index 5c8410b..52cecc3 100644 --- a/.gdbinit +++ b/.gdbinit @@ -1,5 +1,6 @@ file sysroot/boot/kernel target remote localhost:1234 +break int_handler_breakpoint define q monitor quit @@ -21,3 +22,17 @@ define reset monitor system_reset end +define restore_env +set $name = $arg0 +python +registers = ['rax', 'rbx', 'rcx', 'rdx', 'rsi', + 'rdi', 'rbp', 'rsp', 'r8', 'r9', 'r10', 'r11', + 'r12', 'r13', 'r14', 'r15', 'rip'] +values = {} +for r in registers: + values[r] = gdb.parse_and_eval('$name->{}'.format(r)) + +for r in registers: + gdb.parse_and_eval('${}={}'.format(r, values[r])) +gdb.execute('frame 0') +end diff --git a/kernel/Makefile b/kernel/Makefile index 13467ec..657641d 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -10,8 +10,8 @@ endif # Find all source files and corresponding object files -KERNEL_SRC := $(wildcard **/*.[cS]) -KERNEL_OBJS := $(addprefix obj/,$(patsubst %,%.o,$(basename $(KERNEL_SRC)))) +KERNEL_SRC := $(wildcard **/*.[cS]*) +KERNEL_OBJS := $(addprefix obj/,$(patsubst %,%.o,$(basename $(basename $(KERNEL_SRC))))) # Kernel object file KERNEL := obj/boot/kernel @@ -21,7 +21,7 @@ VERSION_OBJ := obj/boot/version.o # Default compilation flags CFLAGS ?= -Wall -Wextra -CFLAGS += -ffreestanding -mcmodel=large +CFLAGS += -ffreestanding -mcmodel=large -mno-red-zone CPPFLAGS += -Iinclude # Optimize only if not debugging ifdef NDEBUG @@ -69,6 +69,8 @@ obj/%.o: %.c obj/%.d $(COMPILE.c) $(DEPFLAGS) $< -o $@ obj/%.o: %.S obj/%.d $(COMPILE.S) $(DEPFLAGS) $< -o $@ +%.S: %.S.py + python $^ > $@ obj/%.d: ; # For installing stuff @@ -86,3 +88,4 @@ clean: -include $(KERNEL_DEP) .PHONY: all clean install install-kernel +.INTERMEDIATE: $(basename $(filter %.py, $(KERNEL_SRC))) diff --git a/kernel/arch/registers.S b/kernel/arch/registers.S new file mode 100644 index 0000000..fa5a1da --- /dev/null +++ b/kernel/arch/registers.S @@ -0,0 +1,23 @@ +.intel_syntax noprefix + +.global load_idt +load_idt: + lidt [rdi] + ret + +.global read_cr0 +read_cr0: + mov rax, cr0 + ret +.global read_cr2 +read_cr2: + mov rax, cr2 + ret +.global read_cr3 +read_cr3: + mov rax, cr3 + ret +.global read_cr4 +read_cr4: + mov rax, cr4 + ret diff --git a/kernel/boot/debug.c b/kernel/boot/debug.c index 195e75b..6d28e3f 100644 --- a/kernel/boot/debug.c +++ b/kernel/boot/debug.c @@ -1,9 +1,11 @@ #include +#include #include #include #include #include #include +#include void debug_init() { @@ -130,3 +132,15 @@ void debug_printf(char *str, ...) debug_vprintf(str, args); va_end(args); } + +void print_registers(registers_t *r) +{ + debug("Num:%x Error:%x\n", r->int_no, r->err_code); + debug("RAX:%x RBX:%x RCX:%x RDX:%x\n", r->rax, r->rbx, r->rcx, r->rdx); + debug("RSI:%x RDI:%x RBP:%x RSP:%x\n", r->rsi, r->rdi, r->rbp, r->rsp); + debug("R8:%x R9:%x R10:%x R11:%x\n", r->r8, r->r9, r->r10, r->r11); + debug("R12:%x R13:%x R14:%x R15:%x\n", r->r12, r->r13, r->r14, r->r15); + debug("RIP:%x RFL:%x\n", r->rip, r->rflags); + debug("CS:%x SS:%x\n", r->cs, r->ss); + debug("CR0:%x CR2:%x CR3:%x CR4:%x\n", read_cr0(), read_cr2(), read_cr3(), read_cr4()); +} diff --git a/kernel/boot/kmain.c b/kernel/boot/kmain.c index a529885..dc5ad99 100644 --- a/kernel/boot/kmain.c +++ b/kernel/boot/kmain.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -8,8 +9,15 @@ int kmain(uint64_t multiboot_magic, void *multiboot_data) debug_ok("MITTOS64 kernel booted\n"); debug_build_time(); debug_git_info(); + + interrupt_init(); multiboot_init(multiboot_magic, P2V(multiboot_data)); debug_info("BOOT COMPLETE\n"); + // Cause a divide-by-zero exception + int a = 5, b = 0; + int c = a/b; + (void)c; + for(;;)asm("hlt"); } diff --git a/kernel/include/debug.h b/kernel/include/debug.h index 7173b9d..dd7a35b 100644 --- a/kernel/include/debug.h +++ b/kernel/include/debug.h @@ -1,5 +1,6 @@ #pragma once #include +#include #ifndef NDEBUG #define debug(...) debug_printf(__VA_ARGS__) @@ -29,3 +30,4 @@ char *_kernel_git_branch; void debug_build_time(); void debug_git_info(); +void print_registers(registers_t *); diff --git a/kernel/include/int.h b/kernel/include/int.h new file mode 100644 index 0000000..84f1588 --- /dev/null +++ b/kernel/include/int.h @@ -0,0 +1,90 @@ +#pragma once + +#define IDT_CALL 0x0C +#define IDT_INTERRUPT 0x0E +#define IDT_TRAP 0x0F +#define IDT_DPL0 0x00 +#define IDT_DPL3 0x60 +#define IDT_PRESENT 0x80 + +#define NUM_INTERRUPTS 256 + +#define INT_DE 0x00 // Divide by zero exception +#define INT_DB 0x01 // Debug exception +#define INT_NMI 0x02 // Non-maskable Interrupt exception +#define INT_BP 0x03 // Beakpoint exception +#define INT_OF 0x04 // Overflow exception +#define INT_BR 0x05 // Bound Range exception +#define INT_UD 0x06 // Invalid Opcode exception +#define INT_NM 0x07 // Device not Available exception +#define INT_DF 0x08 // Double Fault exception +#define INT_CSO 0x09 // Coprocessor Segment Overrun exception +#define INT_TS 0x0A // Invalid TSS exception +#define INT_NP 0x0B // Segment not Present excepton +#define INT_SS 0x0C // Stack exception +#define INT_GP 0x0D // General Protection Fault exception +#define INT_PF 0x0E // Page Fault exception +// Unused exception 0x0F +#define INT_MF 0x10 // Floating Point exception pending +#define INT_AC 0x11 // Alignment Check exception +#define INT_MC 0x12 // Machine Check exception +#define INT_XF 0x13 // SIMD Floating Point exception +// Unused exception 0x14 - 0x1D +#define INT_SX 0x1E // Security exception +// Unused exception 0x1F +// User interrupts 0x20 and forward + +#ifndef __ASSEMBLER__ +#include + +struct int_gate_descriptor +{ + uint16_t base_l; + uint16_t cs; + uint8_t ist; + uint8_t flags; + uint16_t base_m; + uint32_t base_h; + uint32_t ignored; +} __attribute__ ((packed)); + +struct idtr +{ + uint16_t len; + uint64_t addr; +} __attribute__ ((packed)); + +typedef struct registers_st +{ + uint64_t rax; + uint64_t rbx; + uint64_t rcx; + uint64_t rdx; + uint64_t rsi; + uint64_t rdi; + uint64_t rbp; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + + uint64_t int_no; + uint64_t err_code; + uint64_t rip; + uint64_t cs; + uint64_t rflags; + uint64_t rsp; + uint64_t ss; +}registers_t; + +typedef registers_t *(*int_handler_t)(registers_t *); + +void interrupt_init(); +int_handler_t register_int_handler(uint32_t num, int_handler_t h); +void isr_return(registers_t *r); + +#endif diff --git a/kernel/include/registers.h b/kernel/include/registers.h new file mode 100644 index 0000000..389b55f --- /dev/null +++ b/kernel/include/registers.h @@ -0,0 +1,7 @@ +#pragma once + +void load_idt(void *); +uint64_t read_cr0(); +uint64_t read_cr2(); +uint64_t read_cr3(); +uint64_t read_cr4(); diff --git a/kernel/interrupts/interrupts.c b/kernel/interrupts/interrupts.c new file mode 100644 index 0000000..46bbe36 --- /dev/null +++ b/kernel/interrupts/interrupts.c @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include + +struct int_gate_descriptor idt[NUM_INTERRUPTS]; +struct idtr idtr; +int_handler_t int_handlers[NUM_INTERRUPTS]; + +void idt_set(uint32_t num, void *vector, uint16_t cs, uint8_t ist, uint8_t flags) +{ + uintptr_t v = (uintptr_t)vector; + idt[num].base_l = v & 0xFFFF; + idt[num].base_m = (v >> 16) & 0xFFFF; + idt[num].base_h = (v >> 32) & 0xFFFFFFFF; + idt[num].cs = cs; + idt[num].ist = ist; + idt[num].flags = flags; +} + +void interrupt_init() +{ + // Clear IDT and interrupt handler list + memset(idt, 0, sizeof(idt)); + memset(int_handlers, 0, sizeof(int_handlers)); + + // Register all vectors in the IDT + extern void *isr_table[]; + for(int i=0; i < NUM_INTERRUPTS; i++) + { + idt_set(i, isr_table[i], 0x8, 0, + (IDT_PRESENT | IDT_DPL0 | IDT_INTERRUPT)); + } + + // Setup pointer and load IDT + idtr.addr = (uint64_t)idt; + idtr.len = sizeof(idt)-1; + load_idt(&idtr); +} + +int_handler_t register_int_handler(uint32_t num, int_handler_t h) +{ + // Replace the handler for an interrupt + // Return the old handler + int_handler_t old = int_handlers[num]; + int_handlers[num] = h; + return old; +} + + +registers_t *int_handler(registers_t *r) +{ + // If a handler is registered, pass everything onto it + if(int_handlers[r->int_no]) + return int_handlers[r->int_no](r); + + debug("\n===============================================================================\n"); + debug_error("Unhandled interrupt!\n"); + print_registers(r); + +#ifndef NDEBUG + asm("int_handler_breakpoint:"); +#endif + + for(;;); +} diff --git a/kernel/interrupts/isr.S.py b/kernel/interrupts/isr.S.py new file mode 100644 index 0000000..7372a88 --- /dev/null +++ b/kernel/interrupts/isr.S.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +print(''' +.intel_syntax noprefix +.extern isr_common +''') + +print('// Interrupt Service Routines') +for i in range(255): + print('''isr{0}: + cli + {1} + push {0} + jmp isr_common + '''.format(i, + 'push 0' if i not in [8, 10, 11, 12, 13, 14, 17] else 'nop')) + +print(''' + +// Vector table + +.section .data +.global isr_table +isr_table: +''') +for i in range(255): + print(' .quad isr{}'.format(i)) diff --git a/kernel/interrupts/isr_common.S b/kernel/interrupts/isr_common.S new file mode 100644 index 0000000..9a2d1fa --- /dev/null +++ b/kernel/interrupts/isr_common.S @@ -0,0 +1,49 @@ +.intel_syntax noprefix + +.extern int_handler +.global isr_common +.global isr_return + +isr_common: + // Push all registers + push r15 + push r14 + push r13 + push r12 + push r11 + push r10 + push r9 + push r8 + push rbp + push rdi + push rsi + push rdx + push rcx + push rbx + push rax + mov rdi, rsp + call int_handler + mov rdi, rax + +isr_return: + // Return and restore stack + mov rsp, rdi + pop rax + pop rbx + pop rcx + pop rdx + pop rsi + pop rdi + pop rbp + pop r8 + pop r9 + pop r10 + pop r11 + pop r12 + pop r13 + pop r14 + pop r15 + // Pop error code and fault number + add rsp, 16 + iretq +