diff options
author | Marvin Borner | 2021-07-05 18:28:40 +0200 |
---|---|---|
committer | Marvin Borner | 2021-07-05 18:28:40 +0200 |
commit | d1476974cd612412eefc40c6dc72ba66191136fd (patch) | |
tree | 74fa7b96337bed895aff5fa268131fc9e3961f97 | |
parent | 4e5b18fb3284705904a2f15f790b8c15b5767fd0 (diff) |
Added interrupt handling
-rw-r--r-- | makefile | 19 | ||||
-rw-r--r-- | src/loader/inc/int.h | 49 | ||||
-rw-r--r-- | src/loader/inc/pic.h | 11 | ||||
-rw-r--r-- | src/loader/int.asm | 151 | ||||
-rw-r--r-- | src/loader/int.c | 144 | ||||
-rw-r--r-- | src/loader/main.c | 10 | ||||
-rw-r--r-- | src/loader/pic.c | 64 |
7 files changed, 441 insertions, 7 deletions
@@ -1,4 +1,5 @@ # MIT License, Copyright (c) 2021 Marvin Borner +# It's not as complicated as it looks # Obviously needs cross compiler CC = $(PWD)/cross/opt/bin/i686-elf-gcc @@ -10,8 +11,13 @@ AS = nasm BLD = $(PWD)/build SRC = $(PWD)/src -SRCS = $(shell find $(SRC)/loader/ -type f -name "*.c") -OBJS = $(patsubst $(SRC)/%.c,$(BLD)/%.o,$(SRCS)) +# C code +CSRCS = $(shell find $(SRC)/loader/ -type f -name "*.c") +COBJS = $(patsubst $(SRC)/%.c,$(BLD)/%_c.o,$(CSRCS)) + +# Assembly code +ASRCS = $(shell find $(SRC)/loader/ -type f -name "*.asm") +AOBJS = $(patsubst $(SRC)/%.asm,$(BLD)/%_asm.o,$(ASRCS)) # Enable many warnings for less bugs :) WARNINGS = -Wall -Wextra -Wshadow -Wpointer-arith -Wwrite-strings -Wredundant-decls -Wnested-externs -Wformat=2 -Wmissing-declarations -Wstrict-prototypes -Wmissing-prototypes -Wcast-qual -Wswitch-default -Wswitch-enum -Wunreachable-code -Wundef -Wold-style-definition -Wvla -pedantic-errors @@ -28,16 +34,19 @@ dir: @mkdir -p $(BLD)/loader/fs/ $(BLD)/boot.bin: $(BLD)/loader.bin - @$(AS) -f bin $(SRC)/entry/bootsector.asm -o $@ + @$(AS) $(ASFLAGS) -f bin $(SRC)/entry/bootsector.asm -o $@ -$(BLD)/loader.o: $(OBJS) +$(BLD)/loader.o: $(COBJS) $(AOBJS) @$(LD) -N -z max-page-size=0x1000 -estart -T$(SRC)/loader/link.ld -o $@ $^ $(BLD)/loader.bin: $(BLD)/loader.o @$(OC) -O binary $^ $@ -$(OBJS): $(BLD)/%.o : $(SRC)/%.c +$(COBJS): $(BLD)/%_c.o : $(SRC)/%.c @$(CC) -c $(CFLAGS) $< -o $@ +$(AOBJS): $(BLD)/%_asm.o : $(SRC)/%.asm + @$(AS) $(ASFLAGS) $< -o $@ + clean: @rm -rf $(BLD)/* diff --git a/src/loader/inc/int.h b/src/loader/inc/int.h new file mode 100644 index 0000000..ccd9ea8 --- /dev/null +++ b/src/loader/inc/int.h @@ -0,0 +1,49 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#ifndef INT_H +#define INT_H + +#include <def.h> + +#define INT_GATE 0x8e +#define INT_TRAP 0xef +#define INT_USER 0x60 +#define IDT_ENTRY(offset, selector, type) \ + (struct idt_entry) \ + { \ + .base_low = (u16)((offset)&0xffff), .sel = (selector), .zero = 0, .flags = (type), \ + .base_high = (u16)(((offset) >> 16) & 0xffff), \ + } + +struct int_frame { + u32 gs, fs, es, ds; + u32 edi, esi, ebp, esp, ebx, edx, ecx, eax; + u32 int_no, err_code; + u32 eip, cs, eflags; +} PACKED; + +struct int_frame_user { + u32 gs, fs, es, ds; + u32 edi, esi, ebp, esp, ebx, edx, ecx, eax; + u32 int_no, err_code; + u32 eip, cs, eflags; + u32 useresp, ss; +} PACKED; + +struct idt_entry { + u16 base_low; + u16 sel; // Kernel segment + u8 zero; // Always 0 + u8 flags; + u16 base_high; +} PACKED; + +struct idt_ptr { + u16 size; + void *base; +} PACKED; + +void idt_install(void); +void int_event_handler_add(u32 int_no, void (*handler)(void)); + +#endif diff --git a/src/loader/inc/pic.h b/src/loader/inc/pic.h new file mode 100644 index 0000000..c2a7d87 --- /dev/null +++ b/src/loader/inc/pic.h @@ -0,0 +1,11 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#ifndef PIC_H +#define PIC_H + +#include <def.h> + +void pic_install(void); +void pic_ack(u32 int_no); + +#endif diff --git a/src/loader/int.asm b/src/loader/int.asm new file mode 100644 index 0000000..f6e66ae --- /dev/null +++ b/src/loader/int.asm @@ -0,0 +1,151 @@ +; MIT License, Copyright (c) 2021 Marvin Borner + +bits 32 + +%macro INT_REGISTER 1 +dd int%1 +%endmacro + +%macro INT_ERR 1 +int%1: + push %1 + jmp int_common +%endmacro + +%macro INT_NOERR 1 +int%1: + push 0 + push %1 + jmp int_common +%endmacro + +extern int_handler +int_common: + cld + + pushad + push ds + push es + push fs + push gs + + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + push esp + call int_handler + mov esp, eax + + pop gs + pop fs + pop es + pop ds + popad + + add esp, 8 + iret + +INT_NOERR 0 +INT_NOERR 1 +INT_NOERR 2 +INT_NOERR 3 +INT_NOERR 4 +INT_NOERR 5 +INT_NOERR 6 +INT_NOERR 7 +INT_ERR 8 +INT_NOERR 9 +INT_ERR 10 +INT_ERR 11 +INT_ERR 12 +INT_ERR 13 +INT_ERR 14 +INT_NOERR 15 +INT_NOERR 16 +INT_ERR 17 +INT_NOERR 18 +INT_NOERR 19 +INT_NOERR 20 +INT_NOERR 21 +INT_NOERR 22 +INT_NOERR 23 +INT_NOERR 24 +INT_NOERR 25 +INT_NOERR 26 +INT_NOERR 27 +INT_NOERR 28 +INT_NOERR 29 +INT_ERR 30 +INT_NOERR 31 + +INT_NOERR 32 +INT_NOERR 33 +INT_NOERR 34 +INT_NOERR 35 +INT_NOERR 36 +INT_NOERR 37 +INT_NOERR 38 +INT_NOERR 39 +INT_NOERR 40 +INT_NOERR 41 +INT_NOERR 42 +INT_NOERR 43 +INT_NOERR 44 +INT_NOERR 45 +INT_NOERR 46 +INT_NOERR 47 + +global int_table +int_table: + INT_REGISTER 0 + INT_REGISTER 1 + INT_REGISTER 2 + INT_REGISTER 3 + INT_REGISTER 4 + INT_REGISTER 5 + INT_REGISTER 6 + INT_REGISTER 7 + INT_REGISTER 8 + INT_REGISTER 9 + INT_REGISTER 10 + INT_REGISTER 11 + INT_REGISTER 12 + INT_REGISTER 13 + INT_REGISTER 14 + INT_REGISTER 15 + INT_REGISTER 16 + INT_REGISTER 17 + INT_REGISTER 18 + INT_REGISTER 19 + INT_REGISTER 20 + INT_REGISTER 21 + INT_REGISTER 22 + INT_REGISTER 23 + INT_REGISTER 24 + INT_REGISTER 25 + INT_REGISTER 26 + INT_REGISTER 27 + INT_REGISTER 28 + INT_REGISTER 29 + INT_REGISTER 30 + INT_REGISTER 31 + + INT_REGISTER 32 + INT_REGISTER 33 + INT_REGISTER 34 + INT_REGISTER 35 + INT_REGISTER 36 + INT_REGISTER 37 + INT_REGISTER 38 + INT_REGISTER 39 + INT_REGISTER 40 + INT_REGISTER 41 + INT_REGISTER 42 + INT_REGISTER 43 + INT_REGISTER 44 + INT_REGISTER 45 + INT_REGISTER 46 + INT_REGISTER 47 diff --git a/src/loader/int.c b/src/loader/int.c new file mode 100644 index 0000000..67b80f0 --- /dev/null +++ b/src/loader/int.c @@ -0,0 +1,144 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#include <int.h> +#include <log.h> +#include <pic.h> +#include <pnc.h> + +/** + * IDT + */ + +extern u32 int_table[]; +static struct idt_entry idt[256] = { 0 }; +static struct idt_ptr idt_ptr = { 0 }; + +void idt_install(void) +{ + idt_ptr.size = sizeof(idt) - 1; + idt_ptr.base = &idt; + + for (u8 i = 0; i < 3; i++) + idt[i] = IDT_ENTRY(int_table[i], 0x08, INT_GATE); + + idt[3] = IDT_ENTRY(int_table[3], 0x08, INT_TRAP); + idt[4] = IDT_ENTRY(int_table[4], 0x08, INT_TRAP); + + for (u8 i = 5; i < 48; i++) + idt[i] = IDT_ENTRY(int_table[i], 0x08, INT_GATE); + + idt[128] = IDT_ENTRY(int_table[48], 0x08, INT_GATE | INT_USER); + idt[129] = IDT_ENTRY(int_table[49], 0x08, INT_GATE); + + // Load table + __asm__ volatile("lidt %0" : : "m"(idt_ptr)); + + // Enable interrupts + __asm__ volatile("sti"); +} + +/** + * Exception (trap) handling + */ + +const char *int_trap_names[32] = { + "Division By Zero", + "Debug", + "Non Maskable Interrupt", + "Breakpoint", + "Into Detected Overflow", + "Out of Bounds", + "Invalid Opcode", + "No Coprocessor", + + "Double Fault", + "Coprocessor Segment Overrun", + "Bad TSS", + "Segment Not Present", + "Stack Fault", + "General Protection Fault", + "Page Fault", + "Unknown Interrupt", + + "Coprocessor Fault", + "Alignment Check", + "Machine Check", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", +}; + +static void int_trap_handler(struct int_frame *frame) +{ + static u8 faulting = 0; + faulting++; + + if (faulting == 2) { + // Fall back to serial driver + serial_print("Double fault, halting immediatly\n"); + while (1) + __asm__ volatile("cli\nhlt"); + } + + log("%s Exception (code %x) at 0x%x!\n", int_trap_names[frame->int_no], frame->err_code, + frame->eip); + + while (1) + __asm__ volatile("cli\nhlt"); +} + +/** + * Event handling + */ + +static void (*int_event_handlers[16])(void) = { 0 }; + +void int_event_handler_add(u32 int_no, void (*handler)(void)) +{ + assert(int_no < COUNT(int_event_handlers)); + int_event_handlers[int_no] = handler; +} + +static u32 int_event_handler(struct int_frame *frame) +{ + u32 int_no = frame->int_no - 32; + assert(int_no < COUNT(int_event_handlers)); + void (*handler)(void) = int_event_handlers[int_no]; + if (handler) + handler(); + + return (u32)frame; +} + +/** + * Universal handler + */ + +static u8 int_enabled = 1; + +u32 int_handler(u32 esp); +u32 int_handler(u32 esp) +{ + struct int_frame *frame = (struct int_frame *)esp; + if (frame->int_no < 32) { + int_trap_handler(frame); + } else if (int_enabled && frame->int_no < 48) { + esp = int_event_handler(frame); + } else if (frame->int_no >= 48) { + panic("Unknown interrupt\n"); + } + + pic_ack(frame->int_no); + return esp; +} diff --git a/src/loader/main.c b/src/loader/main.c index bf2604e..7c50e62 100644 --- a/src/loader/main.c +++ b/src/loader/main.c @@ -3,13 +3,14 @@ #include <def.h> #include <dev.h> #include <ide.h> +#include <int.h> #include <log.h> #include <pci.h> +#include <pic.h> /** * Entry */ -#include <pnc.h> int start(void); int start(void) @@ -17,10 +18,15 @@ int start(void) vga_clear(); serial_install(); + pic_install(); + idt_install(); + pci_probe(); dev_print(); + // Sleep and wait for interrupts while (1) - ; + __asm__ volatile("hlt"); + return 0; } diff --git a/src/loader/pic.c b/src/loader/pic.c new file mode 100644 index 0000000..18b248c --- /dev/null +++ b/src/loader/pic.c @@ -0,0 +1,64 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#include <cpu.h> +#include <pic.h> + +#define PIC1 0x20 +#define PIC1_COMMAND PIC1 +#define PIC1_OFFSET 0x20 +#define PIC1_DATA (PIC1 + 1) + +#define PIC2 0xa0 +#define PIC2_COMMAND PIC2 +#define PIC2_OFFSET 0x28 +#define PIC2_DATA (PIC2 + 1) + +#define ICW1_ICW4 0x01 +#define ICW1_INIT 0x10 + +static void pic_wait(void) +{ + __asm__ volatile("jmp 1f\n\t" + "1:\n\t" + " jmp 2f\n\t" + "2:"); +} + +void pic_install(void) +{ + // Initialize + outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4); + pic_wait(); + outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4); + pic_wait(); + + // Remap + outb(PIC1_DATA, PIC1_OFFSET); + pic_wait(); + outb(PIC2_DATA, PIC2_OFFSET); + pic_wait(); + + outb(PIC1_DATA, 0x04); + pic_wait(); + outb(PIC2_DATA, 0x02); + pic_wait(); + + // Set 8086 mode + outb(PIC1_DATA, 0x01); + pic_wait(); + outb(PIC2_DATA, 0x01); + pic_wait(); + + outb(PIC1_DATA, 0x00); + pic_wait(); + outb(PIC2_DATA, 0x00); + pic_wait(); +} + +void pic_ack(u32 int_no) +{ + if (int_no >= 40) + outb(PIC2, 0x20); + + outb(PIC1, 0x20); +} |