Kaynağa Gözat

refactor(irq): new irq handling method

greatbridf 1 yıl önce
ebeveyn
işleme
12c41b087e

+ 1 - 0
CMakeLists.txt

@@ -62,6 +62,7 @@ set(KERNEL_MAIN_SOURCES src/fs/fat.cpp
                         include/kernel/errno.h
                         include/kernel/tty.hpp
                         include/kernel/interrupt.h
+                        include/kernel/irq.hpp
                         include/kernel/process.hpp
                         include/kernel/syscall.hpp
                         include/kernel/mem.h

+ 3 - 0
gblibc/include/stdint.h

@@ -18,6 +18,9 @@ typedef __UINT16_TYPE__ uint16_t;
 typedef __UINT32_TYPE__ uint32_t;
 typedef __UINT64_TYPE__ uint64_t;
 
+typedef __UINTPTR_TYPE__ uintptr_t;
+typedef __INTPTR_TYPE__ intptr_t;
+
 typedef __SIZE_TYPE__ size_t;
 typedef int32_t ssize_t;
 

+ 2 - 0
include/kernel/hw/keyboard.h

@@ -2,6 +2,8 @@
 
 #include <types/types.h>
 
+// TODO: this whole thing needs rewriting
+
 int32_t keyboard_has_data(void);
 
 void process_keyboard_data(void);

+ 0 - 2
include/kernel/hw/serial.h

@@ -16,8 +16,6 @@ uint8_t serial_read_data(port_id_t port);
 int32_t is_serial_ready_for_transmition(port_id_t port);
 void serial_send_data(port_id_t port, uint8_t data);
 
-void serial_receive_data_interrupt(void);
-
 #ifdef __cplusplus
 }
 #endif

+ 0 - 77
include/kernel/interrupt.h

@@ -49,86 +49,9 @@ struct page_fault_error_code {
     uint32_t software_guard_extensions : 1;
 };
 
-// external interrupt handler function
-// stub in assembly MUST be called irqN
-#define SET_UP_IRQ(N, SELECTOR)        \
-    ptr_t addr_irq##N = (ptr_t)irq##N; \
-    SET_IDT_ENTRY(0x20 + (N), (addr_irq##N), (SELECTOR), KERNEL_INTERRUPT_GATE_TYPE);
-
-#define SET_IDT_ENTRY_FN(N, FUNC_NAME, SELECTOR, TYPE) \
-    extern void FUNC_NAME();                           \
-    ptr_t addr_##FUNC_NAME = (ptr_t)FUNC_NAME;         \
-    SET_IDT_ENTRY((N), (addr_##FUNC_NAME), (SELECTOR), (TYPE));
-
-#define SET_IDT_ENTRY(N, ADDR, SELECTOR, TYPE) \
-    IDT[(N)].offset_low = (ADDR)&0x0000ffff;   \
-    IDT[(N)].selector = (SELECTOR);            \
-    IDT[(N)].zero = 0;                         \
-    IDT[(N)].type_attr = (TYPE);               \
-    IDT[(N)].offset_high = ((ADDR)&0xffff0000) >> 16
-
-struct IDT_entry {
-    uint16_t offset_low;
-    uint16_t selector;
-    uint8_t zero;
-    uint8_t type_attr;
-    uint16_t offset_high;
-};
-
-#ifndef _INTERRUPT_C_
-extern struct IDT_entry IDT[256];
-#endif
-
 void init_idt(void);
 void init_pic(void);
 
-// idt_descriptor: uint16_t[3]
-// [0] bit 0 :15 => limit
-// [1] bit 16:47 => address
-extern void asm_load_idt(uint16_t idt_descriptor[3], int sti);
-
-void int13_handler(
-    struct regs_32 s_regs,
-    uint32_t error_code,
-    ptr_t eip,
-    uint16_t cs,
-    uint32_t eflags);
-
-void int0(void);
-void int1(void);
-void int2(void);
-void int3(void);
-void int4(void);
-void int5(void);
-void int6(void);
-void int7(void);
-void int8(void);
-void int9(void);
-void int10(void);
-void int11(void);
-void int12(void);
-void int13(void);
-void int14(void);
-
-void irq0(void);
-void irq1(void);
-void irq2(void);
-void irq3(void);
-void irq4(void);
-void irq5(void);
-void irq6(void);
-void irq7(void);
-void irq8(void);
-void irq9(void);
-void irq10(void);
-void irq11(void);
-void irq12(void);
-void irq13(void);
-void irq14(void);
-void irq15(void);
-
-void syscall_stub(void);
-
 #ifdef __cplusplus
 }
 #endif

+ 11 - 0
include/kernel/irq.hpp

@@ -0,0 +1,11 @@
+#pragma once
+
+#include <functional>
+
+namespace kernel::irq {
+
+using irq_handler_t = std::function<void()>;
+
+void register_handler(int irqno, irq_handler_t handler);
+
+};

+ 57 - 75
src/asm/interrupt.s

@@ -69,129 +69,111 @@ int14:
     iret
 
 .globl irq0
-.type  irq0 @function
 irq0:
     pushal
-
-    # stack alignment and push *data
-    movl %esp, %eax
-    subl $0x4, %esp
-    andl $0xfffffff0, %esp
-    movl %eax, (%esp)
-
-    call irq0_handler
-
-    # restore stack
-    popl %esp
-
-    popal
-    iret
-
+    mov $0, %eax
+    jmp irqstub
 .globl irq1
-.type  irq1 @function
 irq1:
     pushal
-    call irq1_handler
-    popal
-    iret
-
+    mov $1, %eax
+    jmp irqstub
 .globl irq2
-.type  irq2 @function
 irq2:
     pushal
-    call irq2_handler
-    popal
-    iret
+    mov $2, %eax
+    jmp irqstub
 .globl irq3
-.type  irq3 @function
 irq3:
     pushal
-    call irq3_handler
-    popal
-    iret
+    mov $3, %eax
+    jmp irqstub
 .globl irq4
-.type  irq4 @function
 irq4:
     pushal
-    call irq4_handler
-    popal
-    iret
+    mov $4, %eax
+    jmp irqstub
 .globl irq5
-.type  irq5 @function
 irq5:
     pushal
-    call irq5_handler
-    popal
-    iret
+    mov $5, %eax
+    jmp irqstub
 .globl irq6
-.type  irq6 @function
 irq6:
     pushal
-    call irq6_handler
-    popal
-    iret
+    mov $6, %eax
+    jmp irqstub
 .globl irq7
-.type  irq7 @function
 irq7:
     pushal
-    call irq7_handler
-    popal
-    iret
+    mov $7, %eax
+    jmp irqstub
 .globl irq8
-.type  irq8 @function
 irq8:
     pushal
-    call irq8_handler
-    popal
-    iret
+    mov $8, %eax
+    jmp irqstub
 .globl irq9
-.type  irq9 @function
 irq9:
     pushal
-    call irq9_handler
-    popal
-    iret
+    mov $9, %eax
+    jmp irqstub
 .globl irq10
-.type  irq10 @function
 irq10:
     pushal
-    call irq10_handler
-    popal
-    iret
+    mov $10, %eax
+    jmp irqstub
 .globl irq11
-.type  irq11 @function
 irq11:
     pushal
-    call irq11_handler
-    popal
-    iret
+    mov $11, %eax
+    jmp irqstub
 .globl irq12
-.type  irq12 @function
 irq12:
     pushal
-    call irq12_handler
-    popal
-    iret
+    mov $12, %eax
+    jmp irqstub
 .globl irq13
-.type  irq13 @function
 irq13:
     pushal
-    call irq13_handler
-    popal
-    iret
+    mov $13, %eax
+    jmp irqstub
 .globl irq14
-.type  irq14 @function
 irq14:
     pushal
-    call irq14_handler
-    popal
-    iret
+    mov $14, %eax
+    jmp irqstub
 .globl irq15
-.type  irq15 @function
 irq15:
     pushal
-    call irq15_handler
+    mov $15, %eax
+    jmp irqstub
+
+.globl irqstub
+irqstub:
+    # save current esp
+    mov %esp, %ebx
+
+    # align stack to 16byte boundary
+    and $0xfffffff0, %esp
+
+    # save mmx registers
+    subl $512, %esp
+    fxsave (%esp)
+
+    # push irq number
+    sub $16, %esp
+    mov %eax, (%esp)
+
+    call irq_handler
+
+    # restore mmx registers
+    fxrstor 16(%esp)
+
+    # restore stack and general purpose registers
+    mov %ebx, %esp
     popal
+
     iret
 
 .globl syscall_stub

+ 12 - 8
src/kernel/hw/serial.cpp

@@ -1,9 +1,18 @@
 #include <asm/port_io.h>
 #include <kernel/hw/serial.h>
+#include <kernel/irq.hpp>
 #include <kernel/tty.hpp>
 #include <stdio.h>
 #include <types/status.h>
 
+static void serial_receive_data_interrupt(void)
+{
+    while (is_serial_has_data(PORT_SERIAL0)) {
+        uint8_t data = serial_read_data(PORT_SERIAL0);
+        console->recvchar(data);
+    }
+}
+
 SECTION(".text.kinit")
 int32_t init_serial_port(port_id_t port)
 {
@@ -31,6 +40,9 @@ int32_t init_serial_port(port_id_t port)
     asm_outb(port + 4, 0x0F);
 
     asm_outb(port + 1, 0x01); // Enable interrupts #0: Received Data Available
+
+    kernel::irq::register_handler(4, serial_receive_data_interrupt);
+
     return GB_OK;
 }
 
@@ -57,11 +69,3 @@ void serial_send_data(port_id_t port, uint8_t data)
         ;
     return asm_outb(port, data);
 }
-
-void serial_receive_data_interrupt(void)
-{
-    while (is_serial_has_data(PORT_SERIAL0)) {
-        uint8_t data = serial_read_data(PORT_SERIAL0);
-        console->recvchar(data);
-    }
-}

+ 68 - 97
src/kernel/interrupt.cpp

@@ -1,4 +1,5 @@
-#define _INTERRUPT_C_
+#include <list>
+#include <vector>
 
 #include <asm/port_io.h>
 #include <assert.h>
@@ -6,6 +7,7 @@
 #include <kernel/hw/serial.h>
 #include <kernel/hw/timer.h>
 #include <kernel/interrupt.h>
+#include <kernel/irq.hpp>
 #include <kernel/log.hpp>
 #include <kernel/mem.h>
 #include <kernel/mm.hpp>
@@ -17,6 +19,49 @@
 #include <types/size.h>
 #include <types/types.h>
 
+struct IDT_entry {
+    uint16_t offset_low;
+    uint16_t selector;
+    uint8_t zero;
+    uint8_t type_attr;
+    uint16_t offset_high;
+};
+
+// interrupt stubs
+extern "C" void irq0(); extern "C" void irq1(); extern "C" void irq2();
+extern "C" void irq3(); extern "C" void irq4(); extern "C" void irq5();
+extern "C" void irq6(); extern "C" void irq7(); extern "C" void irq8();
+extern "C" void irq9(); extern "C" void irq10(); extern "C" void irq11();
+extern "C" void irq12(); extern "C" void irq13(); extern "C" void irq14();
+extern "C" void irq15(); extern "C" void int6(); extern "C" void int8();
+extern "C" void int13(); extern "C" void int14();
+extern "C" void syscall_stub();
+
+#define SET_UP_IRQ(N, SELECTOR)                   \
+    ptr_t addr_irq##N = (ptr_t)irq##N;            \
+    set_idt_entry(IDT, 0x20 + (N), (addr_irq##N), \
+        (SELECTOR), KERNEL_INTERRUPT_GATE_TYPE);
+
+#define SET_IDT_ENTRY_FN(N, FUNC_NAME, SELECTOR, TYPE) \
+    ptr_t addr_##FUNC_NAME = (ptr_t)FUNC_NAME;         \
+    set_idt_entry(IDT, (N), (addr_##FUNC_NAME), (SELECTOR), (TYPE));
+
+SECTION(".text.kinit")
+static void set_idt_entry(IDT_entry (&idt)[256], int n,
+    uintptr_t offset, uint16_t selector, uint8_t type)
+{
+    idt[n].offset_low = offset & 0xffff;
+    idt[n].selector = selector;
+    idt[n].zero = 0;
+    idt[n].type_attr = type;
+    idt[n].offset_high = (offset >> 16) & 0xffff;
+}
+
+// idt_descriptor: uint16_t[3]
+// [0] bit 0 :15 => limit
+// [1] bit 16:47 => address
+extern "C" void asm_load_idt(uint16_t idt_descriptor[3], int sti);
+
 static struct IDT_entry IDT[256];
 
 static inline void NORETURN die(regs_32& regs, ptr_t eip)
@@ -60,11 +105,27 @@ void init_idt()
     asm_load_idt(idt_descriptor, 0);
 }
 
+using kernel::irq::irq_handler_t;
+static std::vector<std::list<irq_handler_t>> s_irq_handlers;
+
+void kernel::irq::register_handler(int irqno, irq_handler_t handler)
+{
+    s_irq_handlers[irqno].emplace_back(std::move(handler));
+}
+
 SECTION(".text.kinit")
 void init_pic(void)
 {
     asm_cli();
 
+    s_irq_handlers.resize(16);
+
+    // TODO: move this to timer driver
+    kernel::irq::register_handler(0, []() {
+        inc_tick();
+        schedule();
+    });
+
     asm_outb(PORT_PIC1_COMMAND, 0x11); // edge trigger mode
     asm_outb(PORT_PIC1_DATA, 0x20); // start from int 0x20
     asm_outb(PORT_PIC1_DATA, 0x04); // PIC1 is connected to IRQ2 (1 << 2)
@@ -247,102 +308,12 @@ extern "C" void int14_handler(int14_data* d)
     }
 }
 
-void after_irq(void)
-{
-    check_signal();
-}
-
-extern "C" void irq0_handler(interrupt_stack*)
-{
-    inc_tick();
-    asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
-    schedule();
-    after_irq();
-}
-// keyboard interrupt
-extern "C" void irq1_handler(void)
-{
-    asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
-    handle_keyboard_interrupt();
-    after_irq();
-}
-extern "C" void irq2_handler(void)
-{
-    asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
-    after_irq();
-}
-extern "C" void irq3_handler(void)
-{
-    asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
-    after_irq();
-}
-extern "C" void irq4_handler(void)
-{
-    // TODO: register interrupt handler in serial port driver
-    serial_receive_data_interrupt();
-    asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
-    after_irq();
-}
-extern "C" void irq5_handler(void)
+extern "C" void irq_handler(int irqno)
 {
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
-    after_irq();
-}
-extern "C" void irq6_handler(void)
-{
-    asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
-    after_irq();
-}
-extern "C" void irq7_handler(void)
-{
-    asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
-    after_irq();
-}
-extern "C" void irq8_handler(void)
-{
-    asm_outb(PORT_PIC2_COMMAND, PIC_EOI);
-    asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
-    after_irq();
-}
-extern "C" void irq9_handler(void)
-{
-    asm_outb(PORT_PIC2_COMMAND, PIC_EOI);
-    asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
-    after_irq();
-}
-extern "C" void irq10_handler(void)
-{
-    asm_outb(PORT_PIC2_COMMAND, PIC_EOI);
-    asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
-    after_irq();
-}
-extern "C" void irq11_handler(void)
-{
-    asm_outb(PORT_PIC2_COMMAND, PIC_EOI);
-    asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
-    after_irq();
-}
-extern "C" void irq12_handler(void)
-{
-    asm_outb(PORT_PIC2_COMMAND, PIC_EOI);
-    asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
-    after_irq();
-}
-extern "C" void irq13_handler(void)
-{
-    asm_outb(PORT_PIC2_COMMAND, PIC_EOI);
-    asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
-    after_irq();
-}
-extern "C" void irq14_handler(void)
-{
-    asm_outb(PORT_PIC2_COMMAND, PIC_EOI);
-    asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
-    after_irq();
-}
-extern "C" void irq15_handler(void)
-{
-    asm_outb(PORT_PIC2_COMMAND, PIC_EOI);
-    asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
-    after_irq();
+    if (irqno >= 8)
+        asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
+
+    for (const auto& handler : s_irq_handlers[irqno])
+        handler();
 }

+ 2 - 0
src/kernel/process.cpp

@@ -451,6 +451,8 @@ bool schedule()
     asm_ctx_switch(&curr_thd->esp, thd->esp);
 
 _end:
+
+    check_signal();
     return current_process->signals.empty();
 }
 

+ 3 - 3
src/kinit.cpp

@@ -101,14 +101,14 @@ extern "C" SECTION(".text.kinit") void NORETURN kernel_init(void)
         (*ctor)();
     }
 
-    int ret = init_serial_port(PORT_SERIAL0);
-    assert(ret == GB_OK);
-
     init_idt();
     init_mem();
     init_pic();
     init_pit();
 
+    int ret = init_serial_port(PORT_SERIAL0);
+    assert(ret == GB_OK);
+
     ret = init_console("ttyS0");
     assert(ret == GB_OK);