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
