:: commit cddacc280a67f9f5196b3f02c3e18790dd75df45

mintsuki <mintsuki@protonmail.com> — 2020-01-25 01:05

parents: 9b5c159d1f

Add IDT and PIT driver

diff --git a/src/lib/blib.c b/src/lib/blib.c
index 5d7635c0..701528e5 100644
--- a/src/lib/blib.c
+++ b/src/lib/blib.c
@@ -4,6 +4,14 @@
 #include <lib/blib.h>
 #include <drivers/vga_textmode.h>
 #include <lib/real.h>
+#include <sys/interrupt.h>
+
+void pit_sleep(uint64_t pit_ticks) {
+    uint64_t target = global_pit_tick + pit_ticks;
+    while (global_pit_tick < target) {
+        asm volatile ("hlt");
+    }
+}
 
 uint64_t strtoui(const char *s) {
     uint64_t n = 0;
diff --git a/src/lib/blib.h b/src/lib/blib.h
index dd27a00d..aa1a8bd9 100644
--- a/src/lib/blib.h
+++ b/src/lib/blib.h
@@ -2,6 +2,9 @@
 #define __LIB__BLIB_H__
 
 #include <stddef.h>
+#include <stdint.h>
+
+void pit_sleep(uint64_t pit_ticks);
 
 void print(const char *fmt, ...);
 char getchar(void);
diff --git a/src/lib/real.c b/src/lib/real.c
index ca41cbd2..08eec87f 100644
--- a/src/lib/real.c
+++ b/src/lib/real.c
@@ -25,6 +25,18 @@ void rm_int(
         "push ebp\n\t"
         "pushf\n\t"
 
+        "cli\n\t"
+
+        "mov dx, 0x21\n\t"
+        "mov al, byte ptr ds:[rm_pic0_mask]\n\t"
+        "out dx, al\n\t"
+        "mov dx, 0xa1\n\t"
+        "mov al, byte ptr ds:[rm_pic1_mask]\n\t"
+        "out dx, al\n\t"
+
+        "sidt [8f]\n\t"
+        "lidt [9f]\n\t"
+
         // Jump to real mode
         "jmp 0x08:1f\n\t"
         "1: .code16\n\t"
@@ -59,10 +71,14 @@ void rm_int(
         "pop eax\n\t"
         "mov esp, dword ptr ds:[5f]\n\t"
 
+        "sti\n\t"
+
         // Indirect interrupt call
         ".byte 0xcd\n\t"
         "3: .byte 0\n\t"
 
+        "cli\n\t"
+
         // Load out_regs
         "mov dword ptr ds:[5f], esp\n\t"
         "mov esp, dword ptr ds:[6f]\n\t"
@@ -90,6 +106,15 @@ void rm_int(
         "mov gs, ax\n\t"
         "mov ss, ax\n\t"
 
+        "mov dx, 0x21\n\t"
+        "mov al, byte ptr ds:[pm_pic0_mask]\n\t"
+        "out dx, al\n\t"
+        "mov dx, 0xa1\n\t"
+        "mov al, byte ptr ds:[pm_pic1_mask]\n\t"
+        "out dx, al\n\t"
+
+        "lidt [8f]\n\t"
+
         // Restore non-scratch GPRs
         "popf\n\t"
         "pop ebp\n\t"
@@ -106,5 +131,11 @@ void rm_int(
         "6: .long 0\n\t"
         // in_regs
         "7: .long 0\n\t"
+        // pmode IDT
+        "8: .short 0\n\t"
+        "   .long  0\n\t"
+        // rmode IDT
+        "9: .short 0x3ff\n\t"
+        "   .long  0\n\t"
     );
 }
diff --git a/src/main.c b/src/main.c
index bb7b412a..a8fd145e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -11,6 +11,7 @@ asm (
 #include <lib/mbr.h>
 #include <lib/config.h>
 #include <fs/echfs.h>
+#include <sys/interrupt.h>
 
 #define CONFIG_NAME "qloader2.cfg"
 
@@ -26,6 +27,9 @@ void main(int boot_drive) {
 
     // Initial prompt.
     init_vga_textmode();
+
+    init_idt();
+
     print("qLoader 2\n\n");
     print("=> Boot drive: %x\n", boot_drive);
 
diff --git a/src/sys/interrupt.c b/src/sys/interrupt.c
new file mode 100644
index 00000000..b71f375f
--- /dev/null
+++ b/src/sys/interrupt.c
@@ -0,0 +1,66 @@
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/interrupt.h>
+#include <lib/cio.h>
+#include <lib/blib.h>
+
+volatile uint64_t global_pit_tick = 0;
+
+__attribute__((interrupt)) static void unhandled_int(void *r) {
+    (void)r;
+    print("Warning: unhandled interrupt");
+}
+
+__attribute__((interrupt)) static void pit_irq(void *r) {
+    (void)r;
+    global_pit_tick++;
+    port_out_b(0x20, 0x20);
+}
+
+uint8_t rm_pic0_mask = 0xff;
+uint8_t rm_pic1_mask = 0xff;
+uint8_t pm_pic0_mask = 0xff;
+uint8_t pm_pic1_mask = 0xff;
+
+#define IDT_MAX_ENTRIES 16
+
+static struct idt_entry_t idt[IDT_MAX_ENTRIES];
+
+void init_idt(void) {
+    rm_pic0_mask = port_in_b(0x21);
+    rm_pic1_mask = port_in_b(0xa1);
+
+    for (int i = 0; i < IDT_MAX_ENTRIES; i++) {
+        register_interrupt_handler(i, unhandled_int, 0x8e);
+    }
+
+    register_interrupt_handler(0x08, pit_irq, 0x8e);
+
+    struct idt_ptr_t idt_ptr = {
+        sizeof(idt) - 1,
+        (uint32_t)idt
+    };
+
+    asm volatile (
+        "lidt %0"
+        :
+        : "m" (idt_ptr)
+    );
+
+    pm_pic0_mask = 0xfe;
+    pm_pic1_mask = 0xff;
+    port_out_b(0x21, pm_pic0_mask);
+    port_out_b(0xa1, pm_pic1_mask);
+
+    asm volatile ("sti");
+}
+
+void register_interrupt_handler(size_t vec, void *handler, uint8_t type) {
+    uint32_t p = (uint32_t)handler;
+
+    idt[vec].offset_lo = (uint16_t)p;
+    idt[vec].selector = 0x18;
+    idt[vec].unused = 0;
+    idt[vec].type_attr = type;
+    idt[vec].offset_hi = (uint16_t)(p >> 16);
+}
diff --git a/src/sys/interrupt.h b/src/sys/interrupt.h
new file mode 100644
index 00000000..d03b5cdb
--- /dev/null
+++ b/src/sys/interrupt.h
@@ -0,0 +1,30 @@
+#ifndef __SYS__INTERRUPT_H__
+#define __SYS__INTERRUPT_H__
+
+#include <stdint.h>
+#include <stddef.h>
+
+extern volatile uint64_t global_pit_tick;
+
+extern uint8_t rm_pic0_mask;
+extern uint8_t rm_pic1_mask;
+extern uint8_t pm_pic0_mask;
+extern uint8_t pm_pic1_mask;
+
+struct idt_entry_t {
+    uint16_t offset_lo;
+    uint16_t selector;
+    uint8_t unused;
+    uint8_t type_attr;
+    uint16_t offset_hi;
+} __attribute__((packed));
+
+struct idt_ptr_t {
+    uint16_t size;
+    uint32_t address;
+} __attribute__((packed));
+
+void init_idt(void);
+void register_interrupt_handler(size_t, void *, uint8_t);
+
+#endif
tab: 248 wrap: offon