[INTERRUPTS] Exception handling
This commit is contained in:
parent
0120df249e
commit
5dd42d26ae
15
.gdbinit
15
.gdbinit
@ -1,5 +1,6 @@
|
|||||||
file sysroot/boot/kernel
|
file sysroot/boot/kernel
|
||||||
target remote localhost:1234
|
target remote localhost:1234
|
||||||
|
break int_handler_breakpoint
|
||||||
|
|
||||||
define q
|
define q
|
||||||
monitor quit
|
monitor quit
|
||||||
@ -21,3 +22,17 @@ define reset
|
|||||||
monitor system_reset
|
monitor system_reset
|
||||||
end
|
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
|
||||||
|
@ -10,8 +10,8 @@ endif
|
|||||||
|
|
||||||
|
|
||||||
# Find all source files and corresponding object files
|
# Find all source files and corresponding object files
|
||||||
KERNEL_SRC := $(wildcard **/*.[cS])
|
KERNEL_SRC := $(wildcard **/*.[cS]*)
|
||||||
KERNEL_OBJS := $(addprefix obj/,$(patsubst %,%.o,$(basename $(KERNEL_SRC))))
|
KERNEL_OBJS := $(addprefix obj/,$(patsubst %,%.o,$(basename $(basename $(KERNEL_SRC)))))
|
||||||
|
|
||||||
# Kernel object file
|
# Kernel object file
|
||||||
KERNEL := obj/boot/kernel
|
KERNEL := obj/boot/kernel
|
||||||
@ -21,7 +21,7 @@ VERSION_OBJ := obj/boot/version.o
|
|||||||
|
|
||||||
# Default compilation flags
|
# Default compilation flags
|
||||||
CFLAGS ?= -Wall -Wextra
|
CFLAGS ?= -Wall -Wextra
|
||||||
CFLAGS += -ffreestanding -mcmodel=large
|
CFLAGS += -ffreestanding -mcmodel=large -mno-red-zone
|
||||||
CPPFLAGS += -Iinclude
|
CPPFLAGS += -Iinclude
|
||||||
# Optimize only if not debugging
|
# Optimize only if not debugging
|
||||||
ifdef NDEBUG
|
ifdef NDEBUG
|
||||||
@ -69,6 +69,8 @@ obj/%.o: %.c obj/%.d
|
|||||||
$(COMPILE.c) $(DEPFLAGS) $< -o $@
|
$(COMPILE.c) $(DEPFLAGS) $< -o $@
|
||||||
obj/%.o: %.S obj/%.d
|
obj/%.o: %.S obj/%.d
|
||||||
$(COMPILE.S) $(DEPFLAGS) $< -o $@
|
$(COMPILE.S) $(DEPFLAGS) $< -o $@
|
||||||
|
%.S: %.S.py
|
||||||
|
python $^ > $@
|
||||||
obj/%.d: ;
|
obj/%.d: ;
|
||||||
|
|
||||||
# For installing stuff
|
# For installing stuff
|
||||||
@ -86,3 +88,4 @@ clean:
|
|||||||
-include $(KERNEL_DEP)
|
-include $(KERNEL_DEP)
|
||||||
|
|
||||||
.PHONY: all clean install install-kernel
|
.PHONY: all clean install install-kernel
|
||||||
|
.INTERMEDIATE: $(basename $(filter %.py, $(KERNEL_SRC)))
|
||||||
|
23
kernel/arch/registers.S
Normal file
23
kernel/arch/registers.S
Normal 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
|
@ -1,9 +1,11 @@
|
|||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
|
#include <int.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <vga.h>
|
#include <vga.h>
|
||||||
#include <serial.h>
|
#include <serial.h>
|
||||||
|
#include <registers.h>
|
||||||
|
|
||||||
void debug_init()
|
void debug_init()
|
||||||
{
|
{
|
||||||
@ -130,3 +132,15 @@ void debug_printf(char *str, ...)
|
|||||||
debug_vprintf(str, args);
|
debug_vprintf(str, args);
|
||||||
va_end(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());
|
||||||
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
|
#include <int.h>
|
||||||
#include <multiboot.h>
|
#include <multiboot.h>
|
||||||
#include <mem.h>
|
#include <mem.h>
|
||||||
|
|
||||||
@ -8,8 +9,15 @@ int kmain(uint64_t multiboot_magic, void *multiboot_data)
|
|||||||
debug_ok("MITTOS64 kernel booted\n");
|
debug_ok("MITTOS64 kernel booted\n");
|
||||||
debug_build_time();
|
debug_build_time();
|
||||||
debug_git_info();
|
debug_git_info();
|
||||||
|
|
||||||
|
interrupt_init();
|
||||||
multiboot_init(multiboot_magic, P2V(multiboot_data));
|
multiboot_init(multiboot_magic, P2V(multiboot_data));
|
||||||
|
|
||||||
debug_info("BOOT COMPLETE\n");
|
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");
|
for(;;)asm("hlt");
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <int.h>
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#define debug(...) debug_printf(__VA_ARGS__)
|
#define debug(...) debug_printf(__VA_ARGS__)
|
||||||
@ -29,3 +30,4 @@ char *_kernel_git_branch;
|
|||||||
void debug_build_time();
|
void debug_build_time();
|
||||||
void debug_git_info();
|
void debug_git_info();
|
||||||
|
|
||||||
|
void print_registers(registers_t *);
|
||||||
|
90
kernel/include/int.h
Normal file
90
kernel/include/int.h
Normal 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
|
7
kernel/include/registers.h
Normal file
7
kernel/include/registers.h
Normal 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();
|
67
kernel/interrupts/interrupts.c
Normal file
67
kernel/interrupts/interrupts.c
Normal 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(;;);
|
||||||
|
}
|
28
kernel/interrupts/isr.S.py
Normal file
28
kernel/interrupts/isr.S.py
Normal 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))
|
49
kernel/interrupts/isr_common.S
Normal file
49
kernel/interrupts/isr_common.S
Normal 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
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user