Implement a GDT, IDT with ISR and IRQ

Basically, added error handling, interrupts and basic hardware communication is now possible. Yay.
This commit is contained in:
Jenny Curle 2019-04-07 23:43:09 +01:00
parent 388834ef8a
commit 31d2e10b69
11 changed files with 306 additions and 137 deletions

View File

@ -35,9 +35,4 @@ _start:
.size _start, . - _start .size _start, . - _start
.global idt_load
.extern idtp
idt_load:
lidt (idtp)
ret

View File

@ -1,10 +1,10 @@
; This file is written with Intel ASM Syntax. ; This file is written with Intel ASM Syntax.
[GLOBAL load_gdt] ; Allows the C code to call gdt_flush(). [GLOBAL load_gdt] ; Allows the C code to call gdt_flush().
[EXTERN gp]
load_gdt: load_gdt:
mov eax, [esp+4] ; Get the pointer to the GDT, passed as a parameter. ; Get the pointer to the GDT, passed as a parameter.
lgdt [eax] ; Load the new GDT pointer lgdt [gp] ; Load the new GDT pointer
mov ax, 0x10 ; 0x10 is the offset in the GDT to our data segment mov ax, 0x10 ; 0x10 is the offset in the GDT to our data segment
mov ds, ax ; Load all data segment selectors mov ds, ax ; Load all data segment selectors
@ -12,6 +12,6 @@ load_gdt:
mov fs, ax mov fs, ax
mov gs, ax mov gs, ax
mov ss, ax mov ss, ax
jmp 0x08:.flush ; 0x08 is the offset to our code segment: Far jump! jmp 0x08:flush ; 0x08 is the offset to our code segment: Far jump!
.flush: flush:
ret ret

View File

@ -21,7 +21,7 @@
cli cli
push byte 0 push byte 0
push byte %2 push byte %2
jmp isr_common jmp irq_common
%endmacro %endmacro
ISR 0 ISR 0
@ -57,6 +57,22 @@ ISR 29
ISR_ERR 30 ISR_ERR 30
ISR 31 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 extern fault_handler
@ -85,3 +101,35 @@ isr_common:
popa popa
add esp, 8 add esp, 8
iret 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

View File

@ -4,7 +4,8 @@ KERNEL_ARCH_LDFLAGS=
KERNEL_ARCH_LIBS= KERNEL_ARCH_LIBS=
KERNEL_ARCH_OBJS= \ KERNEL_ARCH_OBJS= \
$(ARCHDIR)/boot.o \ $(ARCHDIR)/boot.o \
$(ARCHDIR)/gdt.o \ $(ARCHDIR)/gdt.o \
$(ARCHDIR)/isr.o \ $(ARCHDIR)/isr.o \
$(ARCHDIR)/sys_clock.o \
$(ARCHDIR)/tty.o $(ARCHDIR)/tty.o

21
arch/i386/sys_clock.c Executable file
View File

@ -0,0 +1,21 @@
#include <kernel/utils.h>
#include <kernel/descriptor_tables.h>
#include <kernel/serial.h>
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);
}

View File

@ -3,6 +3,7 @@
#include <stdint.h> #include <stdint.h>
void gdt_set_gate(int, unsigned long, unsigned long, unsigned char, unsigned char); void gdt_set_gate(int, unsigned long, unsigned long, unsigned char, unsigned char);
void gdt_install(); void gdt_install();
@ -16,4 +17,103 @@ typedef struct registers {
uint32_t eip, cs, eflags, useresp, ss; uint32_t eip, cs, eflags, useresp, ss;
} registers_t; } registers_t;
void isr_install(); //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"
};

View File

@ -21,7 +21,7 @@ struct gdt_ptr {
struct gdt_item gdt[3]; //3-entry gdt struct gdt_item gdt[3]; //3-entry gdt
struct gdt_ptr gp; struct gdt_ptr gp;
extern void load_gdt(uint32_t); extern void load_gdt();
void gdt_set_gate(int num, uint32_t base, void gdt_set_gate(int num, uint32_t base,
uint32_t limit, uint8_t access, uint32_t limit, uint8_t access,
@ -52,5 +52,5 @@ void gdt_install() {
gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF);
//Apply changes //Apply changes
load_gdt((uint32_t) &gp); load_gdt();
} }

View File

@ -1,4 +1,5 @@
#include <kernel/utils.h> #include <kernel/utils.h>
#include <kernel/descriptor_tables.h>
struct idt_entry { struct idt_entry {
unsigned short base_low; unsigned short base_low;
@ -11,7 +12,7 @@ struct idt_entry {
struct idt_ptr { struct idt_ptr {
unsigned short limit; unsigned short limit;
unsigned int base; unsigned int base;
}__attribute__((packed)); } __attribute__((packed));
struct idt_entry idt[256]; // Interrupt table of 256 entries struct idt_entry idt[256]; // Interrupt table of 256 entries
struct idt_ptr idtp; // Pointer to idt table 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() { void idt_install() {
idtp.limit = (sizeof (struct idt_entry) * 256) - 1; idtp.limit = (sizeof (struct idt_entry) * 256) - 1;
idtp.base = &idt; idtp.base = (uint16_t) &idt;
memset(&idt, 0, sizeof(struct idt_entry) * 256); 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(); 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);
} }

View File

@ -2,114 +2,4 @@
#include <kernel/tty.h> #include <kernel/tty.h>
#include <kernel/utils.h> #include <kernel/utils.h>
#include <stdint.h> #include <stdint.h>
//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(;;);
}
}

View File

@ -11,16 +11,23 @@ int kernel_main(void) {
// Prepare the serial console. // Prepare the serial console.
init_serial(); init_serial();
serial_print(0x3F8, "[INFO] Serial ready.\n"); serial_print(0x3F8, "[INFO] Serial ready.\r\n");
// Prepare the GDT // Prepare the GDT
serial_print(0x3F8, "[INFO] Beginning GDT subroutine.\n"); serial_print(0x3F8, "[INFO] Beginning GDT subroutine.\r\n");
gdt_install(); gdt_install();
serial_print(0x3F8, "[INFO] GDT subroutine complete.\r\n");
// Prepare interrupts // Prepare interrupts
serial_print(0x3F8, "[INFO] Beginning IDT subroutine.\n"); serial_print(0x3F8, "[INFO] Beginning IDT subroutine.\r\n");
idt_install(); 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. //Print a copyright message.
term_writes("(c)"); term_writes("(c)");
@ -31,6 +38,14 @@ int kernel_main(void) {
term_setcolor(WHITE); 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(;;) {} for(;;) {}
return 0; return 0;
} }

View File

@ -33,7 +33,6 @@ kernel/utils.o \
kernel/serial.o \ kernel/serial.o \
kernel/gdt.o \ kernel/gdt.o \
kernel/idt.o \ kernel/idt.o \
kernel/isr.o \
kernel/kernel.o kernel/kernel.o
OBJS=\ OBJS=\