From 31d2e10b692ddbad72cc590d561bdeaa3c90b729 Mon Sep 17 00:00:00 2001 From: Jenny Curle Date: Sun, 7 Apr 2019 23:43:09 +0100 Subject: [PATCH] Implement a GDT, IDT with ISR and IRQ Basically, added error handling, interrupts and basic hardware communication is now possible. Yay. --- arch/i386/boot.s | 5 -- arch/i386/gdt.s | 10 +-- arch/i386/isr.s | 52 +++++++++++++- arch/i386/make.config | 7 +- arch/i386/sys_clock.c | 21 ++++++ include/kernel/descriptor_tables.h | 102 +++++++++++++++++++++++++- kernel/gdt.c | 4 +- kernel/idt.c | 106 ++++++++++++++++++++++++++- kernel/isr.c | 110 ----------------------------- kernel/kernel.c | 25 +++++-- makefile | 1 - 11 files changed, 306 insertions(+), 137 deletions(-) create mode 100755 arch/i386/sys_clock.c diff --git a/arch/i386/boot.s b/arch/i386/boot.s index 16fa856..9554b9b 100755 --- a/arch/i386/boot.s +++ b/arch/i386/boot.s @@ -35,9 +35,4 @@ _start: .size _start, . - _start -.global idt_load -.extern idtp -idt_load: - lidt (idtp) - ret \ No newline at end of file diff --git a/arch/i386/gdt.s b/arch/i386/gdt.s index e4fd2b4..1da1011 100755 --- a/arch/i386/gdt.s +++ b/arch/i386/gdt.s @@ -1,10 +1,10 @@ ; This file is written with Intel ASM Syntax. [GLOBAL load_gdt] ; Allows the C code to call gdt_flush(). - +[EXTERN gp] load_gdt: - mov eax, [esp+4] ; Get the pointer to the GDT, passed as a parameter. - lgdt [eax] ; Load the new GDT pointer + ; Get the pointer to the GDT, passed as a parameter. + lgdt [gp] ; Load the new GDT pointer mov ax, 0x10 ; 0x10 is the offset in the GDT to our data segment mov ds, ax ; Load all data segment selectors @@ -12,6 +12,6 @@ load_gdt: mov fs, ax mov gs, ax mov ss, ax - jmp 0x08:.flush ; 0x08 is the offset to our code segment: Far jump! -.flush: + jmp 0x08:flush ; 0x08 is the offset to our code segment: Far jump! +flush: ret \ No newline at end of file diff --git a/arch/i386/isr.s b/arch/i386/isr.s index 1a08674..75e3af3 100755 --- a/arch/i386/isr.s +++ b/arch/i386/isr.s @@ -21,7 +21,7 @@ cli push byte 0 push byte %2 - jmp isr_common + jmp irq_common %endmacro ISR 0 @@ -56,7 +56,23 @@ ISR 28 ISR 29 ISR_ERR 30 ISR 31 - + +IRQ 0, 32 +IRQ 1, 33 +IRQ 2, 34 +IRQ 3, 35 +IRQ 4, 36 +IRQ 5, 37 +IRQ 6, 38 +IRQ 7, 39 +IRQ 8, 40 +IRQ 9, 41 +IRQ 10, 42 +IRQ 11, 43 +IRQ 12, 44 +IRQ 13, 45 +IRQ 14, 46 +IRQ 15, 47 extern fault_handler @@ -85,3 +101,35 @@ isr_common: popa add esp, 8 iret + +extern irq_handler + +irq_common: + pusha + push ds + push es + push fs + push gs + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov eax, esp + push eax + mov eax, irq_handler + call eax + pop eax + pop gs + pop fs + pop es + pop ds + popa + add esp, 8 + iret + +global idt_load +extern idtp +idt_load: + lidt [idtp] + ret \ No newline at end of file diff --git a/arch/i386/make.config b/arch/i386/make.config index a5f7c22..1872f9d 100755 --- a/arch/i386/make.config +++ b/arch/i386/make.config @@ -4,7 +4,8 @@ KERNEL_ARCH_LDFLAGS= KERNEL_ARCH_LIBS= KERNEL_ARCH_OBJS= \ -$(ARCHDIR)/boot.o \ -$(ARCHDIR)/gdt.o \ -$(ARCHDIR)/isr.o \ +$(ARCHDIR)/boot.o \ +$(ARCHDIR)/gdt.o \ +$(ARCHDIR)/isr.o \ +$(ARCHDIR)/sys_clock.o \ $(ARCHDIR)/tty.o \ No newline at end of file diff --git a/arch/i386/sys_clock.c b/arch/i386/sys_clock.c new file mode 100755 index 0000000..9c0e067 --- /dev/null +++ b/arch/i386/sys_clock.c @@ -0,0 +1,21 @@ +#include +#include +#include + +size_t timer_ticks = 0; +size_t flag = 0; +void timer_handler(registers_t* r) { + timer_ticks++; + + if(timer_ticks % 18 == 0) { + if(++flag % 2 == 0) { + serial_print(0x3F8, "Tick."); + } else { + serial_print(0x3F8, "Tock."); + } + } +} + +void timer_install() { + irq_install_handler(0, timer_handler); +} \ No newline at end of file diff --git a/include/kernel/descriptor_tables.h b/include/kernel/descriptor_tables.h index 4ba9ce3..cab4560 100755 --- a/include/kernel/descriptor_tables.h +++ b/include/kernel/descriptor_tables.h @@ -3,6 +3,7 @@ #include + void gdt_set_gate(int, unsigned long, unsigned long, unsigned char, unsigned char); void gdt_install(); @@ -16,4 +17,103 @@ typedef struct registers { uint32_t eip, cs, eflags, useresp, ss; } registers_t; -void isr_install(); \ No newline at end of file +//These are all reserved by Intel, and need to be here. +extern void isr0(); +extern void isr1(); +extern void isr2(); +extern void isr3(); +extern void isr4(); +extern void isr5(); +extern void isr6(); +extern void isr7(); +extern void isr8(); +extern void isr9(); +extern void isr10(); +extern void isr11(); +extern void isr12(); +extern void isr13(); +extern void isr14(); +extern void isr15(); +extern void isr16(); +extern void isr17(); +extern void isr18(); +extern void isr19(); +extern void isr20(); +extern void isr21(); +extern void isr22(); +extern void isr23(); +extern void isr24(); +extern void isr25(); +extern void isr26(); +extern void isr27(); +extern void isr28(); +extern void isr29(); +extern void isr30(); +extern void isr31(); + +extern void irq0(); +extern void irq1(); +extern void irq2(); +extern void irq3(); +extern void irq4(); +extern void irq5(); +extern void irq6(); +extern void irq7(); +extern void irq8(); +extern void irq9(); +extern void irq10(); +extern void irq11(); +extern void irq12(); +extern void irq13(); +extern void irq14(); +extern void irq15(); + +static void* irq_routines[16] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +void irq_install_handler(int irq, void (*handler)(registers_t* r)); + +void irq_uninstall_handler(int); + +void irq_install(); + +void irq_handler(registers_t*); + +void timer_install(); + +static const char* exception_messages[] = { + "Division by Zero", + "Debug", + "Non Maskable Interrupt", + "Breakpoint", + "Into Detected Overflow", + "Out of Bounds", + "Invalid Opcode", + "No Coprocessor", + "Double Fault", + "Coprocessor Segment Overrun", + "Bad TSS", + "Segment Not Present", + "Stack Fault", + "General Protection Fault", + "Page Fault", + "Unknown Interrupt", + "Coprocessor Fault", + "Alignment Check", + "Machine Check", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved" +}; \ No newline at end of file diff --git a/kernel/gdt.c b/kernel/gdt.c index a182bc4..ea727b7 100755 --- a/kernel/gdt.c +++ b/kernel/gdt.c @@ -21,7 +21,7 @@ struct gdt_ptr { struct gdt_item gdt[3]; //3-entry gdt struct gdt_ptr gp; -extern void load_gdt(uint32_t); +extern void load_gdt(); void gdt_set_gate(int num, uint32_t base, uint32_t limit, uint8_t access, @@ -52,5 +52,5 @@ void gdt_install() { gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); //Apply changes - load_gdt((uint32_t) &gp); + load_gdt(); } \ No newline at end of file diff --git a/kernel/idt.c b/kernel/idt.c index ef73559..90c2b80 100755 --- a/kernel/idt.c +++ b/kernel/idt.c @@ -1,4 +1,5 @@ #include +#include struct idt_entry { unsigned short base_low; @@ -11,7 +12,7 @@ struct idt_entry { struct idt_ptr { unsigned short limit; unsigned int base; -}__attribute__((packed)); +} __attribute__((packed)); struct idt_entry idt[256]; // Interrupt table of 256 entries struct idt_ptr idtp; // Pointer to idt table @@ -32,11 +33,110 @@ void idt_set_gate(unsigned char num, unsigned long base, unsigned short sel, uns void idt_install() { idtp.limit = (sizeof (struct idt_entry) * 256) - 1; - idtp.base = &idt; + idtp.base = (uint16_t) &idt; memset(&idt, 0, sizeof(struct idt_entry) * 256); - // All ISRs go here + idt_set_gate(0, (unsigned)isr0, 0x08, 0x8E); + idt_set_gate(1, (unsigned)isr1, 0x08, 0x8E); + idt_set_gate(2, (unsigned)isr2, 0x08, 0x8E); + idt_set_gate(3, (unsigned)isr3, 0x08, 0x8E); + idt_set_gate(4, (unsigned)isr4, 0x08, 0x8E); + idt_set_gate(5, (unsigned)isr5, 0x08, 0x8E); + idt_set_gate(6, (unsigned)isr6, 0x08, 0x8E); + idt_set_gate(7, (unsigned)isr7, 0x08, 0x8E); + + idt_set_gate(8, (unsigned)isr8, 0x08, 0x8E); + idt_set_gate(9, (unsigned)isr9, 0x08, 0x8E); + idt_set_gate(10, (unsigned)isr10, 0x08, 0x8E); + idt_set_gate(11, (unsigned)isr11, 0x08, 0x8E); + idt_set_gate(12, (unsigned)isr12, 0x08, 0x8E); + idt_set_gate(13, (unsigned)isr13, 0x08, 0x8E); + idt_set_gate(14, (unsigned)isr14, 0x08, 0x8E); + idt_set_gate(15, (unsigned)isr15, 0x08, 0x8E); + + idt_set_gate(16, (unsigned)isr16, 0x08, 0x8E); + idt_set_gate(17, (unsigned)isr17, 0x08, 0x8E); + idt_set_gate(18, (unsigned)isr18, 0x08, 0x8E); + idt_set_gate(19, (unsigned)isr19, 0x08, 0x8E); + idt_set_gate(20, (unsigned)isr20, 0x08, 0x8E); + idt_set_gate(21, (unsigned)isr21, 0x08, 0x8E); + idt_set_gate(22, (unsigned)isr22, 0x08, 0x8E); + idt_set_gate(23, (unsigned)isr23, 0x08, 0x8E); + + idt_set_gate(24, (unsigned)isr24, 0x08, 0x8E); + idt_set_gate(25, (unsigned)isr25, 0x08, 0x8E); + idt_set_gate(26, (unsigned)isr26, 0x08, 0x8E); + idt_set_gate(27, (unsigned)isr27, 0x08, 0x8E); + idt_set_gate(28, (unsigned)isr28, 0x08, 0x8E); + idt_set_gate(29, (unsigned)isr29, 0x08, 0x8E); + idt_set_gate(30, (unsigned)isr30, 0x08, 0x8E); + idt_set_gate(31, (unsigned)isr31, 0x08, 0x8E); idt_load(); + irq_install(); + +} + +void irq_install_handler(int irq, void (*handler)(registers_t* r)) { + irq_routines[irq] = handler; +} + +void irq_uninstall_handler(int irq) { + irq_routines[irq] = 0; +} + +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, 0x0); + outb(0xA1, 0x0); +} + +void irq_install() { + irq_remap(); + idt_set_gate(32, (unsigned)irq0, 0x08, 0x8E); + idt_set_gate(33, (unsigned)irq1, 0x08, 0x8E); + idt_set_gate(34, (unsigned)irq2, 0x08, 0x8E); + idt_set_gate(35, (unsigned)irq3, 0x08, 0x8E); + idt_set_gate(36, (unsigned)irq4, 0x08, 0x8E); + idt_set_gate(37, (unsigned)irq5, 0x08, 0x8E); + idt_set_gate(38, (unsigned)irq6, 0x08, 0x8E); + idt_set_gate(39, (unsigned)irq7, 0x08, 0x8E); + idt_set_gate(40, (unsigned)irq8, 0x08, 0x8E); + idt_set_gate(41, (unsigned)irq9, 0x08, 0x8E); + idt_set_gate(42, (unsigned)irq10, 0x08, 0x8E); + idt_set_gate(43, (unsigned)irq11, 0x08, 0x8E); + idt_set_gate(44, (unsigned)irq12, 0x08, 0x8E); + idt_set_gate(45, (unsigned)irq13, 0x08, 0x8E); + idt_set_gate(46, (unsigned)irq14, 0x08, 0x8E); + idt_set_gate(47, (unsigned)irq15, 0x08, 0x8E); +} + +void fault_handler(registers_t *r) { + if(r->int_no < 32) { + serial_print(exception_messages[r->int_no], strlen(exception_messages[r->int_no])); + serial_print(" Exception. Halting.\r\n"); + for(;;); + } +} + +void irq_handler(registers_t *r) { + void (*handler)(registers_t* r); + + serial_print(0x3F8, "[INFO] Received IRQ: " + r->int_no); + handler = irq_routines[r->int_no - 32]; + if(handler) + handler(r); + + if(r->int_no > 39) + outb(0xA0, 0x20); + + outb(0x20, 0x20); } \ No newline at end of file diff --git a/kernel/isr.c b/kernel/isr.c index c3c7e6f..8380c6f 100755 --- a/kernel/isr.c +++ b/kernel/isr.c @@ -2,114 +2,4 @@ #include #include #include -//These are all reserved by Intel, and need to be here. -extern void isr0(); -extern void isr1(); -extern void isr2(); -extern void isr3(); -extern void isr4(); -extern void isr5(); -extern void isr6(); -extern void isr7(); -extern void isr8(); -extern void isr9(); -extern void isr10(); -extern void isr11(); -extern void isr12(); -extern void isr13(); -extern void isr14(); -extern void isr15(); -extern void isr16(); -extern void isr17(); -extern void isr18(); -extern void isr19(); -extern void isr20(); -extern void isr21(); -extern void isr22(); -extern void isr23(); -extern void isr24(); -extern void isr25(); -extern void isr26(); -extern void isr27(); -extern void isr28(); -extern void isr29(); -extern void isr30(); -extern void isr31(); -void isr_install() { - idt_set_gate(0, (unsigned)isr0, 0x00, 0x8E); - idt_set_gate(1, (unsigned)isr1, 0x00, 0x8E); - idt_set_gate(2, (unsigned)isr2, 0x00, 0x8E); - idt_set_gate(3, (unsigned)isr3, 0x00, 0x8E); - idt_set_gate(4, (unsigned)isr4, 0x00, 0x8E); - idt_set_gate(5, (unsigned)isr5, 0x00, 0x8E); - idt_set_gate(6, (unsigned)isr6, 0x00, 0x8E); - idt_set_gate(7, (unsigned)isr7, 0x00, 0x8E); - idt_set_gate(8, (unsigned)isr8, 0x00, 0x8E); - idt_set_gate(9, (unsigned)isr9, 0x00, 0x8E); - idt_set_gate(10, (unsigned)isr10, 0x00, 0x8E); - idt_set_gate(11, (unsigned)isr11, 0x00, 0x8E); - idt_set_gate(12, (unsigned)isr12, 0x00, 0x8E); - idt_set_gate(13, (unsigned)isr13, 0x00, 0x8E); - idt_set_gate(14, (unsigned)isr14, 0x00, 0x8E); - idt_set_gate(15, (unsigned)isr15, 0x00, 0x8E); - idt_set_gate(16, (unsigned)isr16, 0x00, 0x8E); - idt_set_gate(17, (unsigned)isr17, 0x00, 0x8E); - idt_set_gate(18, (unsigned)isr18, 0x00, 0x8E); - idt_set_gate(19, (unsigned)isr19, 0x00, 0x8E); - idt_set_gate(20, (unsigned)isr20, 0x00, 0x8E); - idt_set_gate(21, (unsigned)isr21, 0x00, 0x8E); - idt_set_gate(22, (unsigned)isr22, 0x00, 0x8E); - idt_set_gate(23, (unsigned)isr23, 0x00, 0x8E); - idt_set_gate(24, (unsigned)isr24, 0x00, 0x8E); - idt_set_gate(25, (unsigned)isr25, 0x00, 0x8E); - idt_set_gate(26, (unsigned)isr26, 0x00, 0x8E); - idt_set_gate(27, (unsigned)isr27, 0x00, 0x8E); - idt_set_gate(28, (unsigned)isr28, 0x00, 0x8E); - idt_set_gate(29, (unsigned)isr29, 0x00, 0x8E); - idt_set_gate(30, (unsigned)isr30, 0x00, 0x8E); - idt_set_gate(31, (unsigned)isr31, 0x00, 0x8E); -} - -const char* exception_messages[] = { - "Division by Zero", - "Debug", - "Non Maskable Interrupt", - "Breakpoint", - "Into Detected Overflow", - "Out of Bounds", - "Invalid Opcode", - "No Coprocessor", - "Double Fault", - "Coprocessor Segment Overrun", - "Bad TSS", - "Segment Not Present", - "Stack Fault", - "General Protection Fault", - "Page Fault", - "Unknown Interrupt", - "Coprocessor Fault", - "Alignment Check", - "Machine Check", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved" -}; - -void fault_handler(registers_t *r) { - if(r->int_no < 32) { - term_write(exception_messages[r->int_no], strlen(exception_messages[r->int_no])); - puts(" Exception. Halting."); - for(;;); - } -} \ No newline at end of file diff --git a/kernel/kernel.c b/kernel/kernel.c index 6b61f30..291d882 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -11,16 +11,23 @@ int kernel_main(void) { // Prepare the serial console. init_serial(); - serial_print(0x3F8, "[INFO] Serial ready.\n"); + serial_print(0x3F8, "[INFO] Serial ready.\r\n"); // Prepare the GDT - serial_print(0x3F8, "[INFO] Beginning GDT subroutine.\n"); + serial_print(0x3F8, "[INFO] Beginning GDT subroutine.\r\n"); gdt_install(); + serial_print(0x3F8, "[INFO] GDT subroutine complete.\r\n"); // Prepare interrupts - serial_print(0x3F8, "[INFO] Beginning IDT subroutine.\n"); + serial_print(0x3F8, "[INFO] Beginning IDT subroutine.\r\n"); idt_install(); - isr_install(); + serial_print(0x3F8, "[INFO] IDT subroutine complete.\r\n[INFO] Enabling interrupts.\r\n"); + asm volatile("sti"); + + serial_print(0x3F8, "[INFO] Starting System Clock.\r\n"); + timer_install(); + + serial_print(0x3F8, "[INFO] All subsystems ready. Printing message.\r\n"); //Print a copyright message. term_writes("(c)"); @@ -29,7 +36,15 @@ int kernel_main(void) { term_setcolor(RED); term_writes("RED"); term_setcolor(WHITE); - term_writes(", 2019\n"); + term_writes(", 2019\n"); + + serial_print(0x3F8, "[INFO] All operations complete. Checking for other tasks...\r\n"); + + for(size_t i = 0; i < 3000; i++) {} + + serial_print(0x3F8, "[DEBUG] Attempting a Divide by Zero error.\r\n"); + //term_putchar(5/0); + serial_print(0x3F8, "[DEBUG] Survived the error!\r\n"); for(;;) {} return 0; diff --git a/makefile b/makefile index 946f2e4..7122bd5 100755 --- a/makefile +++ b/makefile @@ -33,7 +33,6 @@ kernel/utils.o \ kernel/serial.o \ kernel/gdt.o \ kernel/idt.o \ -kernel/isr.o \ kernel/kernel.o OBJS=\