summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMarvin Borner2021-07-05 18:28:40 +0200
committerMarvin Borner2021-07-05 18:28:40 +0200
commitd1476974cd612412eefc40c6dc72ba66191136fd (patch)
tree74fa7b96337bed895aff5fa268131fc9e3961f97
parent4e5b18fb3284705904a2f15f790b8c15b5767fd0 (diff)
Added interrupt handling
-rw-r--r--makefile19
-rw-r--r--src/loader/inc/int.h49
-rw-r--r--src/loader/inc/pic.h11
-rw-r--r--src/loader/int.asm151
-rw-r--r--src/loader/int.c144
-rw-r--r--src/loader/main.c10
-rw-r--r--src/loader/pic.c64
7 files changed, 441 insertions, 7 deletions
diff --git a/makefile b/makefile
index 7677ff0..288f029 100644
--- a/makefile
+++ b/makefile
@@ -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);
+}