[INTERRUPTS] Exception handling
This commit is contained in:
parent
0120df249e
commit
5dd42d26ae
15
.gdbinit
15
.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
|
||||
|
@ -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
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 <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());
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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
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