From cddacc280a67f9f5196b3f02c3e18790dd75df45 Mon Sep 17 00:00:00 2001 From: mintsuki Date: Sat, 25 Jan 2020 02:05:19 +0100 Subject: [PATCH] Add IDT and PIT driver --- src/lib/blib.c | 8 ++++++ src/lib/blib.h | 3 +++ src/lib/real.c | 31 +++++++++++++++++++++ src/main.c | 4 +++ src/sys/interrupt.c | 66 +++++++++++++++++++++++++++++++++++++++++++++ src/sys/interrupt.h | 30 +++++++++++++++++++++ 6 files changed, 142 insertions(+) create mode 100644 src/sys/interrupt.c create mode 100644 src/sys/interrupt.h 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 #include #include +#include + +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 +#include + +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 #include #include +#include #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 +#include +#include +#include +#include + +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 +#include + +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