[INTERRUPTS] Exception handling

This commit is contained in:
Thomas Lovén 2016-11-20 11:26:32 +01:00
parent 0120df249e
commit 5dd42d26ae
11 changed files with 309 additions and 3 deletions

View File

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

View File

@ -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)))

23
kernel/arch/registers.S Normal file
View File

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

View File

@ -1,9 +1,11 @@
#include <debug.h>
#include <int.h>
#include <stdarg.h>
#include <stdint.h>
#include <string.h>
#include <vga.h>
#include <serial.h>
#include <registers.h>
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());
}

View File

@ -1,4 +1,5 @@
#include <debug.h>
#include <int.h>
#include <multiboot.h>
#include <mem.h>
@ -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");
}

View File

@ -1,5 +1,6 @@
#pragma once
#include <string.h>
#include <int.h>
#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 *);

90
kernel/include/int.h Normal file
View File

@ -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 <stdint.h>
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

View File

@ -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();

View File

@ -0,0 +1,67 @@
#include <int.h>
#include <debug.h>
#include <registers.h>
#include <string.h>
#include <stdint.h>
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(;;);
}

View File

@ -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))

View File

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