[ BIG CHANGE ] Properly Implemented IDT

- New include files: idt.h, pic.h, syscall.h and exceptions.h
- Proper exception handling (still could be improved
- PIC properly initiated and irqs all masked
- BREAKS Keyboard - The keyboard IRQ is not handled anymore
- convertColor() is kinda broken :/ (More in README.md)
This commit is contained in:
2024-05-05 21:03:21 +02:00
parent 29418eb46b
commit 1d71a4e384
15 changed files with 448 additions and 617 deletions
+203
View File
@@ -0,0 +1,203 @@
#ifndef ISRS_H
#define ISRS_H
#include "idt.h"
#include "screen.h"
/*
Alignment Check
Machine Check
Reserved
...
Reserved
*/
// TODO: Make proper handlers
__attribute__ ((naked)) // Temporary handler
void excpHandler(void) {
__asm__ volatile (
".intel_syntax\n"
"iretd\n"
".att_syntax"
);
}
// Exception handlers
__attribute__ ((interrupt))
void excp_divideErr(intFrame_t* iframe) { // ISR 0
fgColor = RED;
print("[ Division Error ]\n");
__asm__ volatile ("cli; hlt"); // Halt system
}
__attribute__ ((interrupt))
void excp_debugErr(intFrame_t* iframe) { // ISR 1
fgColor = RED;
print("[ Debug Exception ]\n");
__asm__ volatile ("cli; hlt");
}
__attribute__ ((interrupt))
void excp_nmiInterrupt(intFrame_t* iframe) { // ISR 2
fgColor = RED;
print("[ Non-maskable Interrupt ]\n");
__asm__ volatile ("cli; hlt");
}
__attribute__ ((interrupt))
void excp_breakpoint(intFrame_t* iframe) { // ISR 3
fgColor = RED;
print("[ Breakpoint ]\n");
__asm__ volatile ("cli; hlt");
}
__attribute__ ((interrupt))
void excp_overflow(intFrame_t* iframe) { // ISR 4
fgColor = RED;
print("[ Overflow Error ]\n");
__asm__ volatile ("cli; hlt");
}
__attribute__ ((interrupt))
void excp_boundRangeExceed(intFrame_t* iframe) { // ISR 5
fgColor = RED;
print("[ Bound Range Exceeded ]\n");
__asm__ volatile ("cli; hlt");
}
__attribute__ ((interrupt))
void excp_invalidOpcode(intFrame_t* iframe) { // ISR 6
fgColor = RED;
print("[ Invalid OpCode ]\n");
__asm__ volatile ("cli; hlt");
}
__attribute__ ((interrupt))
void excp_deviceNA(intFrame_t* iframe) { // ISR 7
fgColor = RED;
print("[ Device Not Available ]\n");
__asm__ volatile ("cli; hlt");
}
__attribute__ ((interrupt))
void excp_doubleFault(intFrame_t* iframe, uint32_t errCode) { // ISR 8
fgColor = RED;
print("[ Double Fault : 0x");
print(itoa(errCode, 16));
print(" ]\n");
__asm__ volatile ("cli; hlt");
}
__attribute__ ((interrupt))
void excp_coprocOverrun(intFrame_t* iframe) { // ISR 9
fgColor = RED;
print("[ Coprocessor Segment Overrun ]\n");
__asm__ volatile ("cli; hlt");
}
__attribute__ ((interrupt))
void excp_invalidTss(intFrame_t* iframe, uint32_t errCode) { // ISR 10
fgColor = RED;
print("[ Invalid TSS : 0x");
print(itoa(errCode, 16));
print(" ]\n");
__asm__ volatile ("cli; hlt");
}
__attribute__ ((interrupt))
void excp_noSegment(intFrame_t* iframe, uint32_t errCode) { // ISR 11
fgColor = RED;
print("[ Segment Not Present : 0x");
print(itoa(errCode, 16));
print(" ]\n");
__asm__ volatile ("cli; hlt");
}
__attribute__ ((interrupt))
void excp_stackSegmentFault(intFrame_t* iframe, uint32_t errCode) { // ISR 12
fgColor = RED;
print("[ Stack-Segment Fault : 0x");
print(itoa(errCode, 16));
print(" ]\n");
__asm__ volatile ("cli; hlt");
}
__attribute__ ((interrupt))
void excp_generalProtectionFault(intFrame_t* iframe, uint32_t errCode) { // ISR 13
fgColor = RED;
print("[ General Protection Fault : 0x");
print(itoa(errCode, 16));
print(" ]\n");
__asm__ volatile ("cli; hlt");
}
__attribute__ ((interrupt))
void excp_pageFault(intFrame_t* iframe, uint32_t errCode) { // ISR 14
fgColor = RED;
print("[ Page Fault : 0x");
print(itoa(errCode, 16));
print(" ]\n");
__asm__ volatile ("cli; hlt");
}
__attribute__ ((interrupt))
void excp_reserved(intFrame_t* iframe) { // ISR 15
fgColor = RED;
print("[ Reserved Exception ]\n"); // Shouldn't get this one
__asm__ volatile ("cli; hlt");
}
__attribute__ ((interrupt))
void excp_floatingPointErr(intFrame_t* iframe) { // ISR 16
fgColor = RED;
print("[ x87 FPU Floating-Point Error ]\n");
__asm__ volatile ("cli; hlt");
}
__attribute__ ((interrupt))
void excp_alignCheck(intFrame_t* iframe, uint32_t errCode) { // ISR 17
fgColor = RED;
print("[ Alignment Check : 0x");
print(itoa(errCode, 16));
print(" ]\n");
__asm__ volatile ("cli; hlt");
}
__attribute__ ((interrupt))
void excp_machineCheck(intFrame_t* iframe) { // ISR 18
fgColor = RED;
print("[ Machine Check ]\n");
__asm__ volatile ("cli; hlt");
}
// TODO: Add more (because there's always more)
// Repetative isr definitions
void setupExceptions() {
for (uint8_t i = 0; i < 32; i++) {
idtSetGate(i, excp_reserved, TRAP_GATE_FLAGS);
}
idtSetGate(0, excp_divideErr, TRAP_GATE_FLAGS);
idtSetGate(1, excp_debugErr, TRAP_GATE_FLAGS);
idtSetGate(2, excp_nmiInterrupt, TRAP_GATE_FLAGS);
idtSetGate(3, excp_breakpoint, TRAP_GATE_FLAGS);
idtSetGate(4, excp_overflow, TRAP_GATE_FLAGS);
idtSetGate(5, excp_boundRangeExceed, TRAP_GATE_FLAGS);
idtSetGate(6, excp_invalidOpcode, TRAP_GATE_FLAGS);
idtSetGate(7, excp_deviceNA, TRAP_GATE_FLAGS);
idtSetGate(8, excp_doubleFault, TRAP_GATE_FLAGS);
idtSetGate(9, excp_coprocOverrun, TRAP_GATE_FLAGS);
idtSetGate(10, excp_invalidTss, TRAP_GATE_FLAGS);
idtSetGate(11, excp_noSegment, TRAP_GATE_FLAGS);
idtSetGate(12, excp_stackSegmentFault, TRAP_GATE_FLAGS);
idtSetGate(13, excp_generalProtectionFault, TRAP_GATE_FLAGS);
idtSetGate(14, excp_pageFault, TRAP_GATE_FLAGS);
idtSetGate(15, excp_reserved, TRAP_GATE_FLAGS);
idtSetGate(16, excp_floatingPointErr, TRAP_GATE_FLAGS);
idtSetGate(17, excp_alignCheck, TRAP_GATE_FLAGS);
idtSetGate(18, excp_machineCheck, TRAP_GATE_FLAGS);
// Other are reserved
}
#endif
+30 -24
View File
@@ -2,48 +2,54 @@
#define IDT_H
#include "stdint.h"
#include "system.h"
#include "screen.h"
struct idtEntry {
#define TRAP_GATE_FLAGS 0x8f // P = 1, DPL = 00, S = 0, Type = 1111 (32-bit Trap gate)
#define INT_GATE_FLAGS 0x8e // P = 1, DPL = 00, S = 0, Type = 1110 (32-bit Int gate)
#define USR_INT_GAME_FLAGS 0xee // P = 1, DPL = 11, S = 0, Type = 1110 (32-bit Int gate)
typedef struct {
uint16_t offsetLow;
uint16_t selector;
uint8_t zero;
uint8_t typeAttr;
uint16_t offsetHigh;
} __attribute__((packed));
} __attribute__ ((packed)) idtEntry_t;
struct idtPointer {
typedef struct {
uint16_t limit;
uint32_t base;
} __attribute__((packed));
} __attribute__ ((packed)) idtp_t;
struct idtEntry idt[256] = { 0 };
struct idtPointer idtp;
typedef struct {
uint32_t eip;
uint32_t cs;
uint32_t eflags;
uint32_t esp;
uint32_t ss;
} __attribute__ ((packed)) intFrame_t;
extern void idtLoad();
__attribute__ ((aligned(0x10))) // For performance
idtEntry_t idt[256] = { 0 };
idtp_t idtp;
void idtSetGate(uint8_t i, uint32_t offset, uint16_t selector, uint8_t typeAttr) {
idt[i].offsetLow = (uint16_t)offset;
idt[i].selector = selector;
idt[i].zero = 0;
idt[i].typeAttr = typeAttr;
idt[i].offsetHigh = (uint16_t)(offset >> 16);
void idtSetGate(uint8_t i, void* handler, uint8_t flags) {
uint32_t offset = (uint32_t)handler;
idtEntry_t* entry = &idt[i];
entry->offsetLow = (uint16_t)offset;
entry->selector = 0x08;
entry->zero = 0;
entry->typeAttr = flags;
entry->offsetHigh = (uint16_t)(offset >> 16);
}
void setupIdt() {
idtp.limit = sizeof(struct idtEntry) * 256;
idtp.limit = sizeof(idtEntry_t) * 256;
idtp.base = (uint32_t)&idt;
idtLoad();
__asm__ volatile ("lidt %0" : : "m"(idtp));
}
// Contains values of registers and exception info from isrs
struct regs {
unsigned int gs, fs, es, ds;
unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax;
unsigned int intNo, errCode;
unsigned int eip, cs, eflags, useresp, ss;
};
#endif
-80
View File
@@ -1,80 +0,0 @@
#ifndef IRQ_H
#define IRQ_H
#include "stdint.h"
#include "idt.h"
void* irqRoutines[16] = { 0 };
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();
void installIrqHandler(uint32_t irq, void (*handler)(struct regs* r)) {
irqRoutines[irq] = handler;
}
void uninstallIrqHandler(uint32_t irq) {
irqRoutines[irq] = 0;
}
void irqHandler(struct regs* r) {
void (*handler)(struct regs* r);
handler = irqRoutines[r->intNo - 32]; // Offset by 32 because of isrs
if (handler) handler(r);
// Something about master and slave handlers
if (r->intNo >= 40) outb(0xa0, 0x20);
outb(0x20, 0x20);
}
void irqRemap(void) {
outb(0xa0, 0x11);
outb(0x20, 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 setupIrqs() {
irqRemap();
// Same as isrs, but differnet handlers :o
idtSetGate(32, (unsigned)irq0, 0x08, 0x8e);
idtSetGate(33, (unsigned)irq1, 0x08, 0x8e);
idtSetGate(34, (unsigned)irq2, 0x08, 0x8e);
idtSetGate(35, (unsigned)irq3, 0x08, 0x8e);
idtSetGate(36, (unsigned)irq4, 0x08, 0x8e);
idtSetGate(37, (unsigned)irq5, 0x08, 0x8e);
idtSetGate(38, (unsigned)irq6, 0x08, 0x8e);
idtSetGate(39, (unsigned)irq7, 0x08, 0x8e);
idtSetGate(40, (unsigned)irq8, 0x08, 0x8e);
idtSetGate(41, (unsigned)irq9, 0x08, 0x8e);
idtSetGate(42, (unsigned)irq10, 0x08, 0x8e);
idtSetGate(43, (unsigned)irq11, 0x08, 0x8e);
idtSetGate(44, (unsigned)irq12, 0x08, 0x8e);
idtSetGate(45, (unsigned)irq13, 0x08, 0x8e);
idtSetGate(46, (unsigned)irq14, 0x08, 0x8e);
idtSetGate(47, (unsigned)irq15, 0x08, 0x8e);
}
#endif
-128
View File
@@ -1,128 +0,0 @@
#ifndef ISRS_H
#define ISRS_H
#include "idt.h"
#include "screen.h"
#include "system.h"
#include "string.h"
char* exceptionMessages[] = {
"Divide By Zero Error",
"Debug Exception",
"NMI Interrupt",
"Breakpoint",
"Overflow",
"BOUND Range Exceeded",
"Invalid Opcode",
"Device Not Available",
"Double Fault",
"Coprocessor Segment Overrun",
"Invalid TSS",
"Segment Not Present",
"Stack-Segment Fault",
"General Protection Fault",
"Page Fault",
"Reserved",
"x87 FPU Floating-Point Error",
"Alignment Check",
"Machine Check",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
};
// Repetative isr definitions
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 setupIsrs() {
idtSetGate(0, (unsigned)isr0, 0x08, 0x8e);
idtSetGate(1, (unsigned)isr1, 0x08, 0x8e);
idtSetGate(2, (unsigned)isr2, 0x08, 0x8e);
idtSetGate(3, (unsigned)isr3, 0x08, 0x8e);
idtSetGate(4, (unsigned)isr4, 0x08, 0x8e);
idtSetGate(5, (unsigned)isr5, 0x08, 0x8e);
idtSetGate(6, (unsigned)isr6, 0x08, 0x8e);
idtSetGate(7, (unsigned)isr7, 0x08, 0x8e);
idtSetGate(8, (unsigned)isr8, 0x08, 0x8e);
idtSetGate(9, (unsigned)isr9, 0x08, 0x8e);
idtSetGate(10, (unsigned)isr10, 0x08, 0x8e);
idtSetGate(11, (unsigned)isr11, 0x08, 0x8e);
idtSetGate(12, (unsigned)isr12, 0x08, 0x8e);
idtSetGate(13, (unsigned)isr13, 0x08, 0x8e);
idtSetGate(14, (unsigned)isr14, 0x08, 0x8e);
idtSetGate(15, (unsigned)isr15, 0x08, 0x8e);
idtSetGate(16, (unsigned)isr16, 0x08, 0x8e);
idtSetGate(17, (unsigned)isr17, 0x08, 0x8e);
idtSetGate(18, (unsigned)isr18, 0x08, 0x8e);
idtSetGate(19, (unsigned)isr19, 0x08, 0x8e);
idtSetGate(20, (unsigned)isr20, 0x08, 0x8e);
idtSetGate(21, (unsigned)isr21, 0x08, 0x8e);
idtSetGate(22, (unsigned)isr22, 0x08, 0x8e);
idtSetGate(23, (unsigned)isr23, 0x08, 0x8e);
idtSetGate(24, (unsigned)isr24, 0x08, 0x8e);
idtSetGate(25, (unsigned)isr25, 0x08, 0x8e);
idtSetGate(26, (unsigned)isr26, 0x08, 0x8e);
idtSetGate(27, (unsigned)isr27, 0x08, 0x8e);
idtSetGate(28, (unsigned)isr28, 0x08, 0x8e);
idtSetGate(29, (unsigned)isr29, 0x08, 0x8e);
idtSetGate(30, (unsigned)isr30, 0x08, 0x8e);
idtSetGate(31, (unsigned)isr31, 0x08, 0x8e);
}
void faultHandler(struct regs* r) {
if (r->intNo < 32) {
print(exceptionMessages[r->intNo]);
if (r->errCode) {
print(": 0x");
print(itoa(r->errCode, 16));
}
cli();
hlt();
}
}
#endif
+3 -2
View File
@@ -1,8 +1,8 @@
#ifndef KEYBOARD_H
#define KEYBOARD_H
#include "irq.h"
#include "idt.h"
#include "pic.h"
#include "system.h"
#include "screen.h"
#include "stdint.h"
@@ -92,7 +92,8 @@ char* read(char terminator) {
}
void setupKeyboard() {
installIrqHandler(1, keyboardHandler);
idtSetGate(33, keyboardHandler, INT_GATE_FLAGS);
setIrqMask(1);
}
#endif
+95
View File
@@ -0,0 +1,95 @@
#ifndef PIC_H
#define PIC_H
#include "system.h"
// PIC I/O Ports
#define PIC_1_CMD 0x20
#define PIC_1_DATA 0x21
#define PIC_2_CMD 0xA0
#define PIC_2_DATA 0xA1
// IRQs
#define NEW_IRQ_0 0x20 // IRQ 0 : int 32
#define NEW_IRQ_8 0x28 // IRQ 8 : int 40
// Commands
#define PIC_EOI 0x20 // End Of Interrupt
#define PIC_DISABLE 0xff
void sendPicEOI(uint8_t irq) {
if (irq >= 8) {
outb(PIC_2_CMD, PIC_EOI);
}
outb(PIC_1_CMD, PIC_EOI);
}
void disableIrqs() {
outb(PIC_2_DATA, PIC_DISABLE);
outb(PIC_1_DATA, PIC_DISABLE);
}
void setIrqMask(uint8_t irq) {
uint16_t port;
uint8_t value;
if (irq < 8) {
port = PIC_1_DATA;
} else {
irq -= 8;
port = PIC_2_DATA;
}
value = inb(port) | (1 << irq);
outb(port, value);
}
void unsetIrqMask(uint8_t irq) {
uint16_t port;
uint8_t value;
if (irq < 8) {
port = PIC_1_DATA;
} else {
irq -= 8;
port = PIC_2_DATA;
}
value = inb(port) & ~(1 << irq);
outb(port, value);
}
void remapPic() {
uint8_t pic1Mask = inb(PIC_1_DATA);
uint8_t pic2Mask = inb(PIC_2_DATA);
// Send Init Control Word 1-4 to both PICs
// ICW 1: bit 0 - send up to 4 ICWs, bit 4 - Init PIC
outb(PIC_1_CMD, 0x11);
ioWait(); // For slower machines
outb(PIC_2_CMD, 0x11);
ioWait();
// ICW 2: Where to map IRW bases in IDT
outb(PIC_1_DATA, NEW_IRQ_0);
ioWait();
outb(PIC_2_DATA, NEW_IRQ_8);
ioWait();
// ICW 3: Which IRQ in PIC1 is PIC2; Mapping PIC2 to IRQ 2
outb(PIC_1_DATA, 0x04);
ioWait();
outb(PIC_2_DATA, 0x02);
ioWait();
// ICW 4 - Set x86 mode
outb(PIC_1_DATA, 0x01);
ioWait();
outb(PIC_2_DATA, 0x01);
ioWait();
outb(PIC_1_DATA, pic1Mask);
outb(PIC_2_DATA, pic2Mask);
}
#endif
+5 -3
View File
@@ -93,9 +93,11 @@ uint32_t convertColor(uint32_t color) {
return color & 0xff;
}
uint8_t red = ((color >> 16) & 0xff) * (((1 << gfxMode->linearRedMaskSize) - 1) / 255.0);
uint8_t green = ((color >> 8 ) & 0xff) * (((1 << gfxMode->linearGreenMaskSize) - 1) / 255.0);
uint8_t blue = ((color ) & 0xff) * (((1 << gfxMode->linearBlueMaskSize) - 1) / 255.0);
// TODO: !! Important !! - Is should be divided by 255.0 (for floats), but using '-mgeneral-regs-only' removes fp-registers and
// wants to use some dumb functions for converting fp numbers in the stdlib (that we don't have)
uint8_t red = ((color >> 16) & 0xff) * (((1 << gfxMode->linearRedMaskSize) - 1) / 255);
uint8_t green = ((color >> 8 ) & 0xff) * (((1 << gfxMode->linearGreenMaskSize) - 1) / 255);
uint8_t blue = ((color ) & 0xff) * (((1 << gfxMode->linearBlueMaskSize) - 1) / 255);
return (red << gfxMode->redFieldPos) | (green << gfxMode->greenFieldPos) | (blue << gfxMode->blueFieldPos);
}
+77
View File
@@ -0,0 +1,77 @@
#ifndef SYSCALL_H
#define SYSCALL_H
#include "screen.h"
// System call count
#define MAX_SYSCALLS 2
void sys_test0() {
fgColor = YELLOW;
print("Syscall 0 - Test\n");
fgColor = FG_COLOR;
}
void sys_test1() {
fgColor = CYAN;
print("Syscall 1 - Test\n");
fgColor = FG_COLOR;
}
// System call table
void* syscalls[MAX_SYSCALLS] = {
sys_test0,
sys_test1,
};
// int 0x80 - Syscall interrupt, handled by this function
// eax : Syscall number
__attribute__ ((naked)) // No prologue or epilogue, just assembly
void syscallHandler(void) {
// Interrupt - Stack should contain: ss, esp, eflags, cs, eip
// We should also push these regs: ax, gs, fs, es, ds, bp, di, si, dx, cx, bx
__asm__ volatile (
".intel_syntax noprefix\n" // We use intel syntax
".equ MAX_SYSCALLS, 2\n" // Define MAX_SYSCALLS again
// Check if syscall exists
"cmp eax, MAX_SYSCALLS - 1\n"
"ja invalidSyscall\n"
// Call the syscall
"push eax\n" // Push required values
"push gs\n"
"push fs\n"
"push es\n"
"push ds\n"
"push ebp\n"
"push edi\n"
"push esi\n"
"push edx\n"
"push ecx\n"
"push ebx\n"
"push esp\n" // Push stack pointer again (for variables and such idk)
"call [syscalls + eax * 4]\n" // Call syscall from table. Syscall number should be in eax
"add esp, 4\n"
"pop ebx\n" // Pop pushed values
"pop ecx\n"
"pop edx\n"
"pop esi\n"
"pop edi\n"
"pop ebp\n"
"pop ds\n"
"pop es\n"
"pop fs\n"
"pop gs\n"
"add esp, 4\n" // Save eax value
"iretd\n" // Return from interrupt
// TODO: Send an error or something here
"invalidSyscall:\n"
"iretd\n"
".att_syntax" // Switch back to Att Syntax (Just in case)
);
}
#endif
+3 -12
View File
@@ -24,18 +24,9 @@ void outw(uint16_t port, uint16_t data) {
asm volatile("outw %0, %1" :: "a"(data), "Nd"(port));
}
// Assembly stuff
void cli() {
asm volatile("cli");
}
void sti() {
asm volatile("sti");
}
void hlt() {
asm volatile("hlt");
void ioWait() {
// Waits ~1 I/O Cycle (Linux uses this so it should be good)
asm volatile("outb %%al, $0x80" : : "a"(0));
}
#endif