]> git.dujemihanovic.xyz Git - nameless-os.git/commitdiff
Rework interrupt handling
authorDuje Mihanović <duje.mihanovic@skole.hr>
Mon, 13 Jun 2022 09:41:50 +0000 (11:41 +0200)
committerDuje Mihanović <duje.mihanovic@skole.hr>
Wed, 22 Jun 2022 16:05:28 +0000 (18:05 +0200)
This new system should, among other things, allow for more flexibility than the
previous one.

TODO: Define interrupt stack frame

Makefile
boot/x86/Makefile
include/arch/x86/irq/idt.h
include/arch/x86/irq/interrupt.h [new file with mode: 0644]
kernel/arch/x86/irq/idt.c
kernel/arch/x86/irq/interrupt.c [new file with mode: 0644]
kernel/arch/x86/irq/sample_handler.c [deleted file]
kernel/arch/x86/irq/stub.s [new file with mode: 0644]
kernel/drivers/input/ps2.c
kernel/kernel.c

index 7d10f975722546a2752b2f85013d8968bf44c375..ae1a7160e9e89533eb315f05771600de91f65ab3 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,12 +1,13 @@
 export AS = yasm
+ASFLAGS = -f elf -g dwarf2
 export CC = i686-elf-gcc
 QEMU = qemu-system-i386 -monitor stdio
 
 export GIT_REV = $(shell git describe --long HEAD)
 
-CFLAGS = -std=gnu89 -g -Iinclude/arch/x86 -ffreestanding -DGIT_COMMIT=\"$(GIT_REV)\"
+CFLAGS = -std=gnu11 -g -Iinclude/arch/x86 -ffreestanding -DGIT_COMMIT=\"$(GIT_REV)\"
 
-KERNEL_OBJ = kernel/entry.o kernel/arch/x86/tty/tty.o kernel/drivers/irq/i8259a.o kernel/arch/x86/irq/idt.o kernel/arch/x86/irq/sample_handler.o kernel/drivers/input/ps2.o kernel/kernel.o
+KERNEL_OBJ = kernel/entry.o kernel/arch/x86/tty/tty.o kernel/drivers/irq/i8259a.o kernel/arch/x86/irq/idt.o kernel/arch/x86/irq/interrupt.o kernel/arch/x86/irq/stub.o kernel/drivers/input/ps2.o kernel/kernel.o
 BOOTLOADER_OBJ = boot/x86/mbr boot/x86/vbr-fat32 boot/x86/stage3/LOADER.BIN
 
 default: kernel/kernel.elf bootloader
@@ -36,12 +37,6 @@ boot/x86/disk.img: boot/x86/mbr boot/x86/vbr-fat32 boot/x86/stage3/LOADER.BIN bo
 kernel/kernel.bin: ${KERNEL_OBJ} kernel/linker.ld
        $(CC) -ffreestanding -nostdlib -o $@ -T kernel/linker.ld ${KERNEL_OBJ}
 
-kernel/entry.o: kernel/entry.s
-       $(AS) -f elf $< -o $@
-
-kernel/arch/x86/irq/sample_handler.o: kernel/arch/x86/irq/sample_handler.c
-       $(CC) $(CFLAGS) -mgeneral-regs-only -c $< -o $@
-
 kernel/drivers/input/ps2.o: kernel/drivers/input/ps2.c
 
 kernel/kernel.o: kernel/kernel.c
index 1de8199c99b304f2de447804485c5f1b14867932..877930a2dba1bebbef0df31bfe0e7557711dfb39 100644 (file)
@@ -1,3 +1,5 @@
+AS = yasm
+ASFLAGS = -f bin
 default: mbr vbr-fat32 stage3/LOADER.BIN
 
 mbr: mbr.s
index daf586f2d5aefe44c723d5f38cb84290f0967472..501e5cd52034b544cbb085f5c71be4784186a599 100644 (file)
@@ -21,7 +21,7 @@ struct idtr {
        uint32_t base; /* starting address of IDT */
 } __attribute__((packed));
 
-extern void idt_set_descriptor(struct idt_descriptor *idt, uint8_t vector, uint16_t segment, uint32_t offset, uint8_t type, uint8_t dpl);
+extern void idt_set_descriptor(struct idt_descriptor *idt, uint8_t vector, uint16_t segment, void (*offset)(void), uint8_t type, uint8_t dpl);
 extern inline void load_idt(struct idtr idtr);
 extern inline void populate_idtr(struct idtr *idtr, struct idt_descriptor *idt);
 
diff --git a/include/arch/x86/irq/interrupt.h b/include/arch/x86/irq/interrupt.h
new file mode 100644 (file)
index 0000000..fbecdd8
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef X86_INTERRUPT_H
+#define X86_INTERRUPT_H
+
+extern int register_interrupt(int irq, int (*handler)(void));
+
+#endif
index 54e8612934ffd9f08751d84cebb59ae5ec1d2227..3871751061001c62d71091d3b24eea1fedf0e880 100644 (file)
@@ -7,17 +7,17 @@ inline void load_idt(struct idtr idtr)
        asm volatile ("lidt %0": : "m" (idtr));
 }
 
-void idt_set_descriptor(struct idt_descriptor *idt, uint8_t vector, uint16_t segment, uint32_t offset, uint8_t type, uint8_t dpl)
+void idt_set_descriptor(struct idt_descriptor *idt, uint8_t vector, uint16_t segment, void (*offset)(void), uint8_t type, uint8_t dpl)
 {
        struct idt_descriptor *descriptor = &idt[vector];
 
-       descriptor->offset_1 = offset & 0xFFFF;
+       descriptor->offset_1 = (uint32_t) offset & 0xFFFF;
        descriptor->segsel = segment;
        descriptor->unused = 0;
        descriptor->type = type;
        descriptor->dpl = dpl;
        descriptor->present = 1;
-       descriptor->offset_2 = offset >> 16;
+       descriptor->offset_2 = (uint32_t) offset >> 16;
 }
 
 inline void populate_idtr(struct idtr *idtr, struct idt_descriptor *idt)
diff --git a/kernel/arch/x86/irq/interrupt.c b/kernel/arch/x86/irq/interrupt.c
new file mode 100644 (file)
index 0000000..b2abef9
--- /dev/null
@@ -0,0 +1,36 @@
+#include <irq/idt.h>
+#include <irq/interrupt.h>
+#include <tty.h>
+#include <stddef.h>
+#include <irq/i8259a.h>
+
+/* This table will hold pointers to our interrupt handlers. */
+static int (*int_handler_table[256])(void);
+
+void int_handler(int interrupt)
+{
+       if (int_handler_table[interrupt] == NULL) {
+               kprint("WARNING: Unhandled interrupt ", 0);
+               kprintb(interrupt);
+               kprint(" occurred!\n", 0);
+       } else {
+               int ret = (*int_handler_table[interrupt])();
+               if (ret) {
+                       kprint("WARNING: Error while handling interrupt ", 0);
+                       kprintb(interrupt);
+                       kprint("!\n", 0);
+               }
+       }
+       if (interrupt >= 0x20) {
+               pic_send_eoi(interrupt - 0x20);
+       }
+}
+
+int register_interrupt(int irq, int (*handler)(void))
+{
+       int_handler_table[irq] = handler;
+       if (irq >= 32 && irq < 48) {
+               pic_unmask(irq-32);
+       }
+       return 0;
+}
diff --git a/kernel/arch/x86/irq/sample_handler.c b/kernel/arch/x86/irq/sample_handler.c
deleted file mode 100644 (file)
index 72a86c6..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-#include <tty.h>
-#include <irq/i8259a.h>
-#include <io.h>
-#include <stdint.h>
-#include <input/ps2.h>
-
-int was_released = 0;
-int is_caps = 0;
-
-typedef uint32_t uword_t;
-
-struct interrupt_frame {
-       uword_t ip;
-       uword_t cs;
-       uword_t flags;
-};
-
-struct abort_frame;
-
-__attribute__((interrupt))
-void keyb_handler(struct interrupt_frame *frame)
-{
-       pic_send_eoi(1);
-       uint8_t scancode = inb(PS2_DATA_PORT);
-       if (was_released) {
-               was_released = 0;
-               return;
-       }
-
-       if (scancode == 0xf0) {
-               was_released = 1;
-               uint8_t scancode = inb(PS2_DATA_PORT);
-               if (scancode == 0x12) {
-                       is_caps = 0;
-               }
-               return;
-       } else {
-               if (scancode == 0x12) {
-                       is_caps = 1;
-                       return;
-               }
-               if (!is_caps) {
-                       kprintc(scancodes[scancode], 0);
-               } else {
-                       kprintc(scancodes[scancode] - ('a'-'A'), 0);
-               }
-       }
-}
-
-
-__attribute__((interrupt))
-void double_fault(struct abort_frame *frame)
-{
-       *(volatile uint32_t *) (0xb8000) = 0xcf28cf3a;
-halt:
-       asm volatile ("cli; hlt");
-       goto halt;
-}
-
diff --git a/kernel/arch/x86/irq/stub.s b/kernel/arch/x86/irq/stub.s
new file mode 100644 (file)
index 0000000..c15969a
--- /dev/null
@@ -0,0 +1,41 @@
+; Stubs for interrupt handlers
+
+bits 32
+section .text
+
+extern int_handler
+
+int_common:
+       cld
+       call int_handler
+       add esp, 4
+       popad
+       iretd
+
+%macro INTERRUPT 1
+global int%1
+int_%1:
+       pushad
+       push dword %1
+       jmp int_common
+%endmacro
+
+%assign i 0
+%rep 48
+INTERRUPT i
+%assign i i+1
+%endrep
+
+; Define flat table containing addresses of handlers
+section .rodata
+global _int_handler_table
+_int_handler_table:
+       %macro INT 1
+               dd int_%1
+       %endmacro
+
+       %assign i 0
+       %rep 48
+       INT i
+       %assign i i+1
+       %endrep
index e765b24bcbcd316fa9448df3cfbacd14afaaa964..ab4be5c5bbcbb9338ed7a545f59dd9517471605f 100644 (file)
@@ -2,11 +2,43 @@
 #include <io.h>
 #include <input/ps2.h>
 #include <bitflags.h>
+#include <irq/interrupt.h>
+
+static int was_released = 0, is_caps = 0;
+
+int ps2_keyb_handler()
+{
+       uint8_t scancode = inb(PS2_DATA_PORT);
+       if (was_released) {
+               was_released = 0;
+               return 0;
+       }
+
+       if (scancode == 0xf0) {
+               was_released = 1;
+               uint8_t scancode = inb(PS2_DATA_PORT);
+               if (scancode == 0x12) {
+                       is_caps = 0;
+               }
+               return 0;
+       } else {
+               if (scancode == 0x12) {
+                       is_caps = 1;
+                       return 0;
+               }
+               if (!is_caps) {
+                       kprintc(scancodes[scancode], 0);
+               } else {
+                       kprintc(scancodes[scancode] - ('a'-'A'), 0);
+               }
+       }
+       return 0;
+}
 
 int ps2_initialize()
 {
        uint8_t ccb, is_2channel, port_1_test, port_2_test;
-       
+
        kprint("ps2: Begin initializing PS/2 controller\n", 0);
        outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_2_DISABLE);
        ps2_input_wait();
@@ -21,7 +53,7 @@ int ps2_initialize()
        CLEAR(ccb, 0);
        CLEAR(ccb, 1);
        CLEAR(ccb, 6);
-       
+
        ps2_input_wait();
        outb(PS2_CMD_STS_PORT, PS2_CMD_WRITE_CCB);
        ps2_input_wait();
@@ -34,7 +66,7 @@ int ps2_initialize()
                kprint("ps2: Controller self test failed, exiting!\n", 0);
                return -1;
        };
-       
+
        ps2_input_wait();
        outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_2_ENABLE);
        ps2_input_wait();
@@ -55,7 +87,7 @@ int ps2_initialize()
        ps2_input_wait();
        outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_1_TEST);
        ps2_output_wait();
-       
+
        if (inb(PS2_DATA_PORT) != 0) {
                port_1_test = 0;
                kprint("ps2: Port 1 test failed!\n", 0);
@@ -87,7 +119,7 @@ int ps2_initialize()
 
        if (port_1_test) {
                uint8_t resp;
-               
+
                do {
                        ps2_input_wait();
                        outb(PS2_DATA_PORT, PS2_DEV_RESET);
@@ -144,6 +176,8 @@ int ps2_initialize()
        ps2_input_wait();
        outb(PS2_DATA_PORT, ccb);
 
+       if (dev_1_test) register_interrupt(33, &ps2_keyb_handler);
+
        if (dev_2_test && dev_1_test) return 1;
        else return 0;
 }
index 3f6c256d8029f2a06429da169381e0b401dea300..2af33720caf647ea2bf8e13a7df572795eb0cd07 100644 (file)
@@ -2,13 +2,13 @@
 #include <tty.h>
 #include <io.h>
 #include <irq/idt.h>
+#include <irq/interrupt.h>
 #include <irq/i8259a.h>
 #include <input/ps2.h>
 
-extern void double_fault(struct abort_frame *frame);
-extern void keyb_handler(struct interrupt_frame *frame);
 struct idt_descriptor idt[256] __attribute__((aligned(0x10)));
 struct idtr idtr __attribute__((aligned(0x10)));
+extern void (*_int_handler_table[48])(void);
 
 void kmain(void)
 {
@@ -17,6 +17,16 @@ void kmain(void)
        kprint("Welcome to Nameless OS!\nRunning revision: ", 0);
        kprint(GIT_COMMIT, 0);
        kprint("\n", 0);
+       kprint("Preparing IDT...\n", 0);
+       for (int i=0; i<48; i++) {
+               idt_set_descriptor(idt, i, 0x8, _int_handler_table[i], IDT_INTERRUPT_GATE, 0);
+       }
+       kprint("IDT prepared, loading...\n", 0);
+       populate_idtr(&idtr, idt);
+       load_idt(idtr);
+       kprint("Setting up interrupts...\n", 0);
+       pic_init(0x20, 0x28);
+       pic_mask_all();
        ps2_success = ps2_initialize();
        switch (ps2_success) {
                case -1:
@@ -28,16 +38,6 @@ void kmain(void)
                case 1:
                        kprint("Found two working PS/2 devices\n", 0);
        }
-       kprint("Preparing IDT...\n", 0);
-       idt_set_descriptor(idt, 0x8, 0x8, (uint32_t) double_fault, IDT_TRAP_GATE, 0x0);
-       idt_set_descriptor(idt, 0x21, 0x8, (uint32_t) keyb_handler, IDT_INTERRUPT_GATE, 0x0);
-       kprint("IDT prepared, loading...\n", 0);
-       populate_idtr(&idtr, idt);
-       load_idt(idtr);
-       kprint("IDT loaded, enabling interrupts...\n", 0);
-       pic_init(0x20, 0x28);
-       pic_mask_all();
-       pic_unmask(1);
        asm volatile ("sti");
        kprint("All done\n", 0);
        while(1);