diff options
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | src/drivers/cpu.c | 12 | ||||
-rw-r--r-- | src/drivers/interrupts.c | 143 | ||||
-rw-r--r-- | src/inc/interrupts.h | 41 | ||||
-rw-r--r-- | src/lib/inc/def.h | 4 | ||||
-rw-r--r-- | src/main.c | 2 |
6 files changed, 196 insertions, 9 deletions
@@ -4,13 +4,14 @@ COBJS = src/main.o \ src/drivers/vesa.o \ src/drivers/cpu.o \ src/drivers/serial.o \ + src/drivers/interrupts.o \ src/lib/string.o CC = cross/opt/bin/i686-elf-gcc LD = cross/opt/bin/i686-elf-ld AS = nasm # TODO: Use lib as external library -CFLAGS = -Wall -Wextra -nostdlib -nostdinc -ffreestanding -std=c99 -pedantic-errors -Isrc/lib/inc/ -Isrc/inc/ -c +CFLAGS = -Wall -Wextra -nostdlib -nostdinc -ffreestanding -mgeneral-regs-only -mno-80387 -std=c99 -pedantic-errors -Isrc/lib/inc/ -Isrc/inc/ -c all: compile clean diff --git a/src/drivers/cpu.c b/src/drivers/cpu.c index eb96562..22691fb 100644 --- a/src/drivers/cpu.c +++ b/src/drivers/cpu.c @@ -6,35 +6,35 @@ u8 inb(u16 port) { u8 value; - __asm__ volatile("inb %1, %0" : "=a"(value) : "Nd"(port)); + __asm__("inb %1, %0" : "=a"(value) : "Nd"(port)); return value; } u16 inw(u16 port) { u16 value; - __asm__ volatile("inw %1, %0" : "=a"(value) : "Nd"(port)); + __asm__("inw %1, %0" : "=a"(value) : "Nd"(port)); return value; } u32 inl(u16 port) { u32 value; - __asm__ volatile("inl %1, %0" : "=a"(value) : "Nd"(port)); + __asm__("inl %1, %0" : "=a"(value) : "Nd"(port)); return value; } void outb(u16 port, u8 data) { - __asm__ volatile("outb %0, %1" ::"a"(data), "Nd"(port)); + __asm__("outb %0, %1" ::"a"(data), "Nd"(port)); } void outw(u16 port, u16 data) { - __asm__ volatile("outw %0, %1" ::"a"(data), "Nd"(port)); + __asm__("outw %0, %1" ::"a"(data), "Nd"(port)); } void outl(u16 port, u32 data) { - __asm__ volatile("outl %0, %1" ::"a"(data), "Nd"(port)); + __asm__("outl %0, %1" ::"a"(data), "Nd"(port)); } diff --git a/src/drivers/interrupts.c b/src/drivers/interrupts.c new file mode 100644 index 0000000..23cbf72 --- /dev/null +++ b/src/drivers/interrupts.c @@ -0,0 +1,143 @@ +// MIT License, Copyright (c) 2020 Marvin Borner + +#include <cpu.h> +#include <def.h> +#include <interrupts.h> +#include <serial.h> + +/** + * IDT + */ + +void idt_set_gate(u8 num, u32 base, u16 sel, u8 flags) +{ + // Specify the interrupt routine's base address + idt[num].base_low = (u16)(base & 0xFFFF); + idt[num].base_high = (u16)((base >> 16) & 0xFFFF); + + // Set selector/segment of IDT entry + idt[num].sel = sel; + idt[num].always0 = 0; + idt[num].flags = (u8)(flags | 0x60); +} + +// Install IDT +void idt_install() +{ + // Set IDT pointer and limit + idt_ptr.limit = (sizeof(struct idt_entry) * 256) - 1; + idt_ptr.base = &idt; + + // Clear IDT by setting memory cells to 0 + //memset(&idt, 0, sizeof(struct idt_entry) * 256); + + __asm__("lidt %0" : : "m"(idt_ptr)); +} + +/** + * IRQ + */ + +void (*irq_routines[16])(struct regs *) = { 0 }; + +// Install IRQ handler +void irq_install_handler(int irq, void (*handler)(struct regs *r)) +{ + irq_routines[irq] = handler; +} + +// Remove IRQ handler +void irq_uninstall_handler(int irq) +{ + irq_routines[irq] = 0; +} + +// Remap the IRQ table +void irq_remap() +{ + outb(0x20, 0x11); + outb(0xA0, 0x11); + outb(0x21, 0x20); + outb(0xA1, 0x28); + outb(0x21, 0x04); + outb(0xA1, 0x02); + outb(0x21, 0x01); + outb(0xA1, 0x01); + outb(0x21, 0x00); + outb(0xA1, 0x00); +} + +// Handle IRQ ISRs +__attribute__((interrupt)) void irq_handler(struct regs *r) +{ + void (*handler)(struct regs * r); + + // Execute custom handler if exists + handler = irq_routines[r->int_no - 32]; + if (handler) + handler(r); + + // Send EOI to second (slave) PIC + if (r->int_no >= 40) + outb(0xA0, 0x20); + + // Send EOI to master PIC + outb(0x20, 0x20); +} + +// Map ISRs to the correct entries in the IDT +void irq_install() +{ + irq_remap(); + for (int i = 32; i < 48; i++) + idt_set_gate(i, (u32)irq_handler, 0x08, 0x8E); +} + +/** + * ISR + */ + +void (*isr_routines[256])(struct regs *) = { 0 }; + +void isr_install_handler(int isr, void (*handler)(struct regs *r)) +{ + isr_routines[isr] = handler; +} + +void isr_uninstall_handler(int isr) +{ + isr_routines[isr] = 0; +} + +__attribute__((interrupt)) void isr_handler(struct regs *r) +{ + void (*handler)(struct regs * r); + + // Execute fault handler if exists + handler = isr_routines[r->int_no]; + if (handler) { + handler(r); + } else { + serial_print("Got ISR!\n"); + __asm__("cli"); + while (1) { + }; + } +} + +void isr_install() +{ + for (int i = 0; i < 32; i++) + idt_set_gate(i, (u32)isr_handler, 0x08, 0x8E); +} + +/** + * Combined + */ +void interrupts_install() +{ + idt_install(); + isr_install(); + irq_install(); + __asm__("sti"); +} diff --git a/src/inc/interrupts.h b/src/inc/interrupts.h new file mode 100644 index 0000000..7145e62 --- /dev/null +++ b/src/inc/interrupts.h @@ -0,0 +1,41 @@ +// MIT License, Copyright (c) 2020 Marvin Borner + +#ifndef IDT_H +#define IDT_H + +#include <def.h> + +struct regs { + u32 gs, fs, es, ds; + u32 edi, esi, ebp, esp, ebx, edx, ecx, eax; + u32 int_no, err_code; + u32 eip, cs, eflags, useresp, ss; +}; + +struct idt_entry { + u16 base_low; + u16 sel; // Kernel segment + u8 always0; // Always 0 + u8 flags; + u16 base_high; +} __attribute__((packed)); + +struct idt_ptr { + u16 limit; + void *base; +} __attribute__((packed)); + +struct idt_entry idt[256]; +struct idt_ptr idt_ptr; + +void idt_set_gate(u8 num, u32 base, u16 sel, u8 flags); + +void irq_install_handler(int irq, void (*handler)(struct regs *r)); +void irq_uninstall_handler(int irq); + +void isr_install_handler(int isr, void (*handler)(struct regs *r)); +void isr_uninstall_handler(int isr); + +void interrupts_install(); + +#endif diff --git a/src/lib/inc/def.h b/src/lib/inc/def.h index 6e3066a..409c0b3 100644 --- a/src/lib/inc/def.h +++ b/src/lib/inc/def.h @@ -13,8 +13,8 @@ typedef unsigned char u8; typedef signed short s16; typedef unsigned short u16; -typedef signed int s32; -typedef unsigned int u32; +typedef signed long s32; +typedef unsigned long u32; typedef signed long long s64; typedef unsigned long long u64; @@ -2,6 +2,7 @@ #include <boot.h> #include <def.h> +#include <interrupts.h> #include <serial.h> #include <vesa.h> @@ -11,6 +12,7 @@ u32 HEAP_START; void main(struct mem_info *mem_info, struct vid_info *vid_info) { HEAP_START = HEAP; // For malloc function + interrupts_install(); mem_info++; // TODO: Use the mmap (or remove)! vbe = vid_info->info; |