diff --git a/Makefile b/Makefile index 71bb68a..4bcb8ab 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ GPPPARAMS = -m32 -fno-use-cxa-atexit -nostdlib -fno-builtin -fno-rtti -fno-excep ASPARAMS = --32 LDPARAMS = -melf_i386 -objs = loader.o gdt.o port.o interruptstubs.o interrupts.o kernel.o +objs = stdio.o loader.o gdt.o port.o interruptstubs.o interrupts.o keyboard.o kernel.o %.o: src/%.cpp g++ $(GPPPARAMS) -o $@ -c $< diff --git a/include/interrupts.h b/include/interrupts.h index 2dc8ee9..1ec2c76 100644 --- a/include/interrupts.h +++ b/include/interrupts.h @@ -4,8 +4,27 @@ #include "port.h" #include "types.h" -class InterruptManager { +class InterruptManager; +class InterruptHandler { protected: + uint8_t _interruptNumber; + InterruptManager* _interruptManager; + + InterruptHandler(uint8_t interruptNumber, InterruptManager* interruptManager); + ~InterruptHandler(); + + public: + virtual uint32_t HandleInterrupt(uint32_t esp); +}; + +class InterruptManager { + friend class InterruptHandler; + + protected: + static InterruptManager* _activeInterruptManager; + + InterruptHandler* _handlers[256]; + struct GateDescriptor { uint16_t handlerAddressLowBits; uint16_t gdt_codeSegmentSelector; @@ -15,7 +34,7 @@ class InterruptManager { } __attribute__((packed)); - static GateDescriptor interruptDescriptorTable[256]; + static GateDescriptor _interruptDescriptorTable[256]; struct InterruptDescriptorTablePointer { uint16_t size; @@ -30,18 +49,20 @@ class InterruptManager { uint8_t descriptorPrivilegeLevel, uint8_t descriptorType); - Port8Bit_Slow picPrimaryCommand; - Port8Bit_Slow picPrimaryData; - Port8Bit_Slow picSecondaryCommand; - Port8Bit_Slow picSecondaryData; + Port8Bit_Slow _picPrimaryCommand; + Port8Bit_Slow _picPrimaryData; + Port8Bit_Slow _picSecondaryCommand; + Port8Bit_Slow _picSecondaryData; public: InterruptManager(GlobalDescriptorTable* gdt); ~InterruptManager(); void Activate(); + void Deactivate(); static uint32_t HandleInterrupt(uint8_t interruptNumber, uint32_t esp); + uint32_t DoHandleInterrupt(uint8_t interruptNumber, uint32_t esp); static void IgnoreInterruptRequest(); static void HandleInterruptRequest0x00(); diff --git a/include/keyboard.cpp b/include/keyboard.cpp new file mode 100644 index 0000000..93bf5d0 --- /dev/null +++ b/include/keyboard.cpp @@ -0,0 +1,168 @@ +#include "../include/keyboard.h" + +#include "../include/stdio.h" + +KeyboardDriver::KeyboardDriver(InterruptManager* manager) : InterruptHandler(0x21, manager), + _dataport(0x60), + _commandport(0x64) { + while (_commandport.Read() & 0x01) { + _dataport.Read(); + } + _commandport.Write(0xAE); + _commandport.Write(0x20); + uint8_t status = (_dataport.Read() | 1) & ~0x10; + _commandport.Write(0x60); + _dataport.Write(status); + + _dataport.Write(0xF4); +} +KeyboardDriver::~KeyboardDriver() {} + +uint32_t KeyboardDriver::HandleInterrupt(uint32_t esp) { + uint8_t key = _dataport.Read(); + if (key < 0x80) { //ignore key up events + switch (key) { + case 0xFA: + case 0x45: + case 0xC5: + break; + case 0x02: + printf("1"); + break; + case 0x03: + printf("2"); + break; + case 0x04: + printf("3"); + break; + case 0x05: + printf("4"); + break; + case 0x06: + printf("5"); + break; + case 0x07: + printf("6"); + break; + case 0x08: + printf("7"); + break; + case 0x09: + printf("8"); + break; + case 0x0A: + printf("9"); + break; + case 0x0B: + printf("0"); + break; + + case 0x10: + printf("q"); + break; + case 0x11: + printf("w"); + break; + case 0x12: + printf("e"); + break; + case 0x13: + printf("r"); + break; + case 0x14: + printf("t"); + break; + case 0x15: + printf("y"); + break; + case 0x16: + printf("u"); + break; + case 0x17: + printf("i"); + break; + case 0x18: + printf("o"); + break; + case 0x19: + printf("p"); + break; + + case 0x1E: + printf("a"); + break; + case 0x1F: + printf("s"); + break; + case 0x20: + printf("d"); + break; + case 0x21: + printf("f"); + break; + case 0x22: + printf("g"); + break; + case 0x23: + printf("h"); + break; + case 0x24: + printf("j"); + break; + case 0x25: + printf("k"); + break; + case 0x26: + printf("l"); + break; + + case 0x2C: + printf("z"); + break; + case 0x2D: + printf("x"); + break; + case 0x2E: + printf("c"); + break; + case 0x2F: + printf("v"); + break; + case 0x30: + printf("b"); + break; + case 0x31: + printf("n"); + break; + case 0x32: + printf("m"); + break; + case 0x33: + printf(","); + break; + case 0x34: + printf("."); + break; + case 0x35: + printf("-"); + break; + + case 0x1C: + printf("\n"); + break; + case 0x39: + printf(" "); + break; + default: + char* foo = "KEYBOARD 0x00"; + char* hex = "0123456789ABCDEF"; + foo[11] = hex[(key >> 4) & 0x0F]; + foo[12] = hex[key & 0x0F]; + printf(foo); + printf("\n"); + break; + } + } + + return esp; +} \ No newline at end of file diff --git a/include/keyboard.h b/include/keyboard.h new file mode 100644 index 0000000..7113961 --- /dev/null +++ b/include/keyboard.h @@ -0,0 +1,19 @@ +#ifndef __KEYBOARD_H +#define __KEYBOARD_H + +#include "interrupts.h" +#include "port.h" +#include "types.h" + +class KeyboardDriver : public InterruptHandler { + private: + Port8Bit _dataport; + Port8Bit _commandport; + + public: + KeyboardDriver(InterruptManager* manager); + ~KeyboardDriver(); + + virtual uint32_t HandleInterrupt(uint32_t esp); +}; +#endif \ No newline at end of file diff --git a/include/mouse.h b/include/mouse.h new file mode 100644 index 0000000..7b86a76 --- /dev/null +++ b/include/mouse.h @@ -0,0 +1,19 @@ +#ifndef __KEYBOARD_H +#define __KEYBOARD_H + +#include "interrupts.h" +#include "port.h" +#include "types.h" + +class MouseDriver : public InterruptHandler { + private: + Port8Bit _dataport; + Port8Bit _commandport; + + public: + MouseDriver(InterruptManager* manager); + ~MouseDriver(); + + virtual uint32_t HandleInterrupt(uint32_t esp); +}; +#endif \ No newline at end of file diff --git a/include/stdio.h b/include/stdio.h new file mode 100644 index 0000000..918edee --- /dev/null +++ b/include/stdio.h @@ -0,0 +1,6 @@ +#ifndef __STDIO_H +#define __STDIO_H + +void printf(const char* str); + +#endif \ No newline at end of file diff --git a/src/interrupts.cpp b/src/interrupts.cpp index ec289fe..114b9ed 100644 --- a/src/interrupts.cpp +++ b/src/interrupts.cpp @@ -1,39 +1,57 @@ #include "../include/interrupts.h" -void printf(char* str); +#include "../include/stdio.h" -InterruptManager::GateDescriptor InterruptManager::interruptDescriptorTable[256]; +InterruptHandler::InterruptHandler(uint8_t interruptNumber, InterruptManager* interruptManager) { + this->_interruptNumber = interruptNumber; + this->_interruptManager = interruptManager; + + interruptManager->_handlers[interruptNumber] = this; +} +InterruptHandler::~InterruptHandler() { + if (_interruptManager->_handlers[_interruptNumber] == this) { + _interruptManager->_handlers[_interruptNumber] = 0; + } +} + +uint32_t InterruptHandler::HandleInterrupt(uint32_t esp) { + return esp; +} + +InterruptManager::GateDescriptor InterruptManager::_interruptDescriptorTable[256]; +InterruptManager* InterruptManager::_activeInterruptManager = 0; InterruptManager::InterruptManager(GlobalDescriptorTable* gdt) - : picPrimaryCommand(0x20), picPrimaryData(0x21), picSecondaryCommand(0xA0), picSecondaryData(0xA1) { + : _picPrimaryCommand(0x20), _picPrimaryData(0x21), _picSecondaryCommand(0xA0), _picSecondaryData(0xA1) { uint16_t codeSegment = gdt->CodeSegmentSelector(); const uint8_t IDT_INTERRUPT_GATE = 0xE; for (uint16_t i = 0; i < 256; i++) { + _handlers[i] = 0; SetInterruptDescriptorTableEntries(i, codeSegment, &IgnoreInterruptRequest, 0, IDT_INTERRUPT_GATE); } // see HandleInterruptRequest in interrupts.s SetInterruptDescriptorTableEntries(0x20, codeSegment, &HandleInterruptRequest0x00, 0, IDT_INTERRUPT_GATE); SetInterruptDescriptorTableEntries(0x21, codeSegment, &HandleInterruptRequest0x01, 0, IDT_INTERRUPT_GATE); - picPrimaryCommand.Write(0x11); - picSecondaryCommand.Write(0x11); + _picPrimaryCommand.Write(0x11); + _picSecondaryCommand.Write(0x11); - picPrimaryData.Write(0x20); - picSecondaryData.Write(0x28); + _picPrimaryData.Write(0x20); + _picSecondaryData.Write(0x28); - picPrimaryData.Write(0x04); - picSecondaryData.Write(0x02); + _picPrimaryData.Write(0x04); + _picSecondaryData.Write(0x02); - picPrimaryData.Write(0x01); - picSecondaryData.Write(0x01); + _picPrimaryData.Write(0x01); + _picSecondaryData.Write(0x01); - picPrimaryData.Write(0x00); - picSecondaryData.Write(0x00); + _picPrimaryData.Write(0x00); + _picSecondaryData.Write(0x00); InterruptDescriptorTablePointer idt; idt.size = 256 * sizeof(GateDescriptor) - 1; - idt.base = (uint32_t)interruptDescriptorTable; + idt.base = (uint32_t)_interruptDescriptorTable; asm volatile("lidt %0" : @@ -42,9 +60,21 @@ InterruptManager::InterruptManager(GlobalDescriptorTable* gdt) InterruptManager::~InterruptManager() {} void InterruptManager::Activate() { + if (_activeInterruptManager != 0) { + _activeInterruptManager->Deactivate(); + } + + _activeInterruptManager = this; asm("sti"); } +void InterruptManager::Deactivate() { + if (_activeInterruptManager == this) { + _activeInterruptManager = 0; + asm("cli"); + } +} + void InterruptManager::SetInterruptDescriptorTableEntries( uint8_t interruptNumber, uint16_t codeSegmentSelectorOffset, @@ -53,14 +83,36 @@ void InterruptManager::SetInterruptDescriptorTableEntries( uint8_t descriptorType) { const uint8_t IDT_DESC_PRESENT = 0x80; - interruptDescriptorTable[interruptNumber].handlerAddressLowBits = ((uint32_t)handler) & 0xFFFF; - interruptDescriptorTable[interruptNumber].handlerAddressHiBits = ((uint32_t)handler >> 16) & 0xFFFF; - interruptDescriptorTable[interruptNumber].gdt_codeSegmentSelector = codeSegmentSelectorOffset; - interruptDescriptorTable[interruptNumber].access = IDT_DESC_PRESENT | descriptorType | ((descriptorPrivilegeLevel & 3) << 5); - interruptDescriptorTable[interruptNumber].reserved = 0; + _interruptDescriptorTable[interruptNumber].handlerAddressLowBits = ((uint32_t)handler) & 0xFFFF; + _interruptDescriptorTable[interruptNumber].handlerAddressHiBits = ((uint32_t)handler >> 16) & 0xFFFF; + _interruptDescriptorTable[interruptNumber].gdt_codeSegmentSelector = codeSegmentSelectorOffset; + _interruptDescriptorTable[interruptNumber].access = IDT_DESC_PRESENT | descriptorType | ((descriptorPrivilegeLevel & 3) << 5); + _interruptDescriptorTable[interruptNumber].reserved = 0; } uint32_t InterruptManager::HandleInterrupt(uint8_t interruptNumber, uint32_t esp) { - printf("INTERRUPT"); + if (_activeInterruptManager != 0) { + return _activeInterruptManager->DoHandleInterrupt(interruptNumber, esp); + } + return esp; +} +uint32_t InterruptManager::DoHandleInterrupt(uint8_t interruptNumber, uint32_t esp) { + if (_handlers[interruptNumber] != 0) { + //we have a handler registered for this interrupt + esp = _handlers[interruptNumber]->HandleInterrupt(esp); + } else if (interruptNumber != 0x20) { + //no handler registered + char* foo = (char*)"UNHANDLED INTERRUPT"; + const char* hex = "0123456789ABCDEF"; + foo[22] = hex[(interruptNumber >> 4) & 0x0F]; + foo[23] = hex[interruptNumber & 0x0F]; + printf(foo); + } + if (0x20 <= interruptNumber && interruptNumber < 0x30) { + _picPrimaryCommand.Write(0x20); + if (0x28 <= interruptNumber && interruptNumber < 0x30) { + _picSecondaryCommand.Write(0x20); + } + } return esp; } diff --git a/src/kernel.cpp b/src/kernel.cpp index e6d7c3d..236566e 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -8,40 +8,10 @@ #include "../include/gdt.h" #include "../include/interrupts.h" +#include "../include/keyboard.h" +#include "../include/stdio.h" #include "../include/types.h" -void printf(char* str) { - static uint16_t* VideoMemory = (uint16_t*)0xb8000; - static uint8_t x = 0, y = 0; - - for (int i = 0; str[i] != '\0'; ++i) { - switch (str[i]) { - case '\n': - y++; - x = 0; - break; - default: - VideoMemory[80 * y + x] = (VideoMemory[80 * y + x] & 0xFF00) | str[i]; - x++; - break; - } - - //line feed after 80 chars (terminal width) - if (x >= 80) { - y++; - x = 0; - } - //we've reached max screen rows - if (y > 25) { - for (y = 0; y < 25; y++) { - for (x - 0; x < 80; x++) { - VideoMemory[80 * y + x] = (VideoMemory[80 * y + x] & 0xFF00) | ' '; - } - } - } - } -} - typedef void (*constructor)(); extern "C" constructor start_ctors; extern "C" constructor end_ctors; @@ -51,13 +21,11 @@ extern "C" void call_constructors() { } extern "C" void ferglos_Main(const void* multiboot_structure, uint32_t /*mb_mag*/) { - printf("Welcome to FerglOS v0.0.2!\n"); - printf("Hitler blinks."); + printf("Welcome to FerglOS v0.0.2!\n\n"); GlobalDescriptorTable gdt; InterruptManager interrupts(&gdt); - - //instantiate hardware in here somewhere + KeyboardDriver keyboard(&interrupts); interrupts.Activate(); diff --git a/src/keyboard.cpp b/src/keyboard.cpp new file mode 100644 index 0000000..7c00e25 --- /dev/null +++ b/src/keyboard.cpp @@ -0,0 +1,179 @@ +#include "../include/keyboard.h" + +#include "../include/stdio.h" + +KeyboardDriver::KeyboardDriver(InterruptManager* manager) : InterruptHandler(0x21, manager), + _dataport(0x60), + _commandport(0x64) { + while (_commandport.Read() & 0x01) { + _dataport.Read(); + } + _commandport.Write(0xAE); + _commandport.Write(0x20); + uint8_t status = (_dataport.Read() | 1) & ~0x10; + _commandport.Write(0x60); + _dataport.Write(status); + + _dataport.Write(0xF4); +} +KeyboardDriver::~KeyboardDriver() {} + +uint32_t KeyboardDriver::HandleInterrupt(uint32_t esp) { + uint8_t key = _dataport.Read(); + static bool __shift = false; + + switch (key) { + case 0xFA: + case 0x45: + case 0xC5: + break; + case 0x02: + __shift ? printf("!") : printf("1"); + break; + case 0x03: + __shift ? printf("\"") : printf("2"); + break; + case 0x04: + __shift ? printf("£") : printf("3"); + break; + case 0x05: + __shift ? printf("$") : printf("4"); + break; + case 0x06: + __shift ? printf("%") : printf("5"); + break; + case 0x07: + __shift ? printf("^") : printf("6"); + break; + case 0x08: + __shift ? printf("&") : printf("7"); + break; + case 0x09: + __shift ? printf("*") : printf("8"); + break; + case 0x0A: + __shift ? printf("(") : printf("9"); + break; + case 0x0B: + __shift ? printf(")") : printf("0"); + break; + + case 0x10: + __shift ? printf("Q") : printf("q"); + break; + case 0x11: + __shift ? printf("W") : printf("w"); + break; + case 0x12: + __shift ? printf("E") : printf("e"); + break; + case 0x13: + __shift ? printf("R") : printf("r"); + break; + case 0x14: + __shift ? printf("T") : printf("t"); + break; + case 0x15: + __shift ? printf("Y") : printf("y"); + break; + case 0x16: + __shift ? printf("U") : printf("u"); + break; + case 0x17: + __shift ? printf("I") : printf("i"); + break; + case 0x18: + __shift ? printf("O") : printf("o"); + break; + case 0x19: + __shift ? printf("P") : printf("p"); + break; + + case 0x1E: + __shift ? printf("A") : printf("a"); + break; + case 0x1F: + __shift ? printf("S") : printf("s"); + break; + case 0x20: + __shift ? printf("D") : printf("d"); + break; + case 0x21: + __shift ? printf("F") : printf("f"); + break; + case 0x22: + __shift ? printf("G") : printf("g"); + break; + case 0x23: + __shift ? printf("H") : printf("h"); + break; + case 0x24: + __shift ? printf("J") : printf("j"); + break; + case 0x25: + __shift ? printf("K") : printf("k"); + break; + case 0x26: + __shift ? printf("L") : printf("l"); + break; + + case 0x2C: + __shift ? printf("Z") : printf("z"); + break; + case 0x2D: + __shift ? printf("X") : printf("x"); + break; + case 0x2E: + __shift ? printf("C") : printf("c"); + break; + case 0x2F: + __shift ? printf("V") : printf("v"); + break; + case 0x30: + __shift ? printf("B") : printf("b"); + break; + case 0x31: + __shift ? printf("N") : printf("n"); + break; + case 0x32: + __shift ? printf("M") : printf("m"); + break; + case 0x33: + __shift ? printf("<") : printf(","); + break; + case 0x34: + __shift ? printf(">") : printf("."); + break; + case 0x35: + __shift ? printf("~") : printf("-"); + break; + + case 0x1C: + __shift ? printf("\n") : printf("\n"); + break; + case 0x39: + __shift ? printf(" ") : printf(" "); + break; + + case 0x2A: + case 0x36: + __shift = true; + break; + case 0xAA: + case 0xB6: + __shift = false; + break; + default: + if (key < 0x80) { //ignore unhandled key up events + char* foo = (char*)"KEYBOARD 0x00"; + const char* hex = "0123456789ABCDEF"; + foo[11] = hex[(key >> 4) & 0x0F]; + foo[12] = hex[key & 0x0F]; + printf(foo); + printf("\n"); + break; + } + } + + return esp; +} \ No newline at end of file diff --git a/src/loader.s b/src/loader.s index 6235380..423826c 100644 --- a/src/loader.s +++ b/src/loader.s @@ -2,7 +2,7 @@ .set FLAGS, (1<<0 | 1<<1) .set CHECKSUM, -(MAGIC + FLAGS) ; #GRUB needs all this stuff, I'll figure out why later -.section multiboot +.section .multiboot .long MAGIC .long FLAGS .long CHECKSUM diff --git a/src/mouse.cpp b/src/mouse.cpp new file mode 100644 index 0000000..656a77b --- /dev/null +++ b/src/mouse.cpp @@ -0,0 +1,167 @@ +#include "../include/keyboard.h" +#include "../include/stdio.h" + +KeyboardDriver::KeyboardDriver(InterruptManager* manager) : InterruptHandler(0x21, manager), + _dataport(0x60), + _commandport(0x64) { + while (_commandport.Read() & 0x01) { + _dataport.Read(); + } + _commandport.Write(0xAE); + _commandport.Write(0x20); + uint8_t status = (_dataport.Read() | 1) & ~0x10; + _commandport.Write(0x60); + _dataport.Write(status); + + _dataport.Write(0xF4); +} +KeyboardDriver::~KeyboardDriver() {} + +uint32_t KeyboardDriver::HandleInterrupt(uint32_t esp) { + uint8_t key = _dataport.Read(); + if (key < 0x80) { //ignore key up events + switch (key) { + case 0xFA: + case 0x45: + case 0xC5: + break; + case 0x02: + printf("1"); + break; + case 0x03: + printf("2"); + break; + case 0x04: + printf("3"); + break; + case 0x05: + printf("4"); + break; + case 0x06: + printf("5"); + break; + case 0x07: + printf("6"); + break; + case 0x08: + printf("7"); + break; + case 0x09: + printf("8"); + break; + case 0x0A: + printf("9"); + break; + case 0x0B: + printf("0"); + break; + + case 0x10: + printf("q"); + break; + case 0x11: + printf("w"); + break; + case 0x12: + printf("e"); + break; + case 0x13: + printf("r"); + break; + case 0x14: + printf("t"); + break; + case 0x15: + printf("y"); + break; + case 0x16: + printf("u"); + break; + case 0x17: + printf("i"); + break; + case 0x18: + printf("o"); + break; + case 0x19: + printf("p"); + break; + + case 0x1E: + printf("a"); + break; + case 0x1F: + printf("s"); + break; + case 0x20: + printf("d"); + break; + case 0x21: + printf("f"); + break; + case 0x22: + printf("g"); + break; + case 0x23: + printf("h"); + break; + case 0x24: + printf("j"); + break; + case 0x25: + printf("k"); + break; + case 0x26: + printf("l"); + break; + + case 0x2C: + printf("z"); + break; + case 0x2D: + printf("x"); + break; + case 0x2E: + printf("c"); + break; + case 0x2F: + printf("v"); + break; + case 0x30: + printf("b"); + break; + case 0x31: + printf("n"); + break; + case 0x32: + printf("m"); + break; + case 0x33: + printf(","); + break; + case 0x34: + printf("."); + break; + case 0x35: + printf("-"); + break; + + case 0x1C: + printf("\n"); + break; + case 0x39: + printf(" "); + break; + default: + char* foo = "KEYBOARD 0x00"; + char* hex = "0123456789ABCDEF"; + foo[11] = hex[(key >> 4) & 0x0F]; + foo[12] = hex[key & 0x0F]; + printf(foo); + printf("\n"); + break; + } + } + + return esp; +} \ No newline at end of file diff --git a/src/stdio.cpp b/src/stdio.cpp new file mode 100644 index 0000000..8ea1f41 --- /dev/null +++ b/src/stdio.cpp @@ -0,0 +1,35 @@ +#include "../include/stdio.h" + +#include "../include/types.h" + +void printf(const char* str) { + static uint16_t* VideoMemory = (uint16_t*)0xb8000; + static uint8_t x = 0, y = 0; + + for (int i = 0; str[i] != '\0'; ++i) { + switch (str[i]) { + case '\n': + y++; + x = 0; + break; + default: + VideoMemory[80 * y + x] = (VideoMemory[80 * y + x] & 0xFF00) | str[i]; + x++; + break; + } + + //line feed after 80 chars (terminal width) + if (x >= 80) { + y++; + x = 0; + } + //we've reached max screen rows + if (y > 25) { + for (y = 0; y < 25; y++) { + for (x - 0; x < 80; x++) { + VideoMemory[80 * y + x] = (VideoMemory[80 * y + x] & 0xFF00) | ' '; + } + } + } + } +}