From ae4265ea5d77b68757af39d73fe47df1a3563b42 Mon Sep 17 00:00:00 2001 From: Aqua-sama Date: Sun, 28 Feb 2021 22:39:25 +0200 Subject: Add keyboard driver --- drivers/keyboard.cc | 147 ++++++++++++++++++++++++++++++++++++++++++++ drivers/keyboard.h | 15 +++++ drivers/makefile | 3 +- drivers/ports.h | 4 +- src/idt.cc | 24 +++++++- src/idt.h | 27 +++++--- src/idt/interruptgate.cc | 10 +++ src/idt/interrupthandler.cc | 14 +++++ src/kernel.cc | 6 ++ src/makefile | 3 +- toolchain.makefile | 2 +- 11 files changed, 241 insertions(+), 14 deletions(-) create mode 100644 drivers/keyboard.cc create mode 100644 drivers/keyboard.h create mode 100644 src/idt/interruptgate.cc create mode 100644 src/idt/interrupthandler.cc diff --git a/drivers/keyboard.cc b/drivers/keyboard.cc new file mode 100644 index 0000000..268ce2b --- /dev/null +++ b/drivers/keyboard.cc @@ -0,0 +1,147 @@ +#include "keyboard.h" +#include + +Keyboard::Keyboard() : InterruptHandler(0x01) { + // eat all previous keystrikes + while (commandport.read() & 0x1) dataport.read(); + commandport.write(0xae); // ??? + commandport.write(0x20); // get state ??? + auto status = (dataport.read() | 1) & ~0x10; + commandport.write(0x60); // set state ??? + dataport.write(status); // ??? + dataport.write(0xf4); // ??? +} + +void Keyboard::trigger() { + const auto key = dataport.read(); + + if (key < 0x80) { + switch (key) { + case 0x04: + printk('3'); + break; + case 0x05: + printk('4'); + break; + case 0x06: + printk('5'); + break; + case 0x07: + printk('6'); + break; + case 0x08: + printk('7'); + break; + case 0x09: + printk('8'); + break; + case 0x0A: + printk('9'); + break; + case 0x0B: + printk('0'); + break; + + case 0x10: + printk('q'); + break; + case 0x11: + printk('w'); + break; + case 0x12: + printk('e'); + break; + case 0x13: + printk('r'); + break; + case 0x14: + printk('t'); + break; + case 0x15: + printk('y'); + break; + case 0x16: + printk('u'); + break; + case 0x17: + printk('i'); + break; + case 0x18: + printk('o'); + break; + case 0x19: + printk('p'); + break; + + case 0x1E: + printk('a'); + break; + case 0x1F: + printk('s'); + break; + case 0x20: + printk('d'); + break; + case 0x21: + printk('f'); + break; + case 0x22: + printk('g'); + break; + case 0x23: + printk('h'); + break; + case 0x24: + printk('j'); + break; + case 0x25: + printk('k'); + break; + case 0x26: + printk('l'); + break; + + case 0x2C: + printk('z'); + break; + case 0x2D: + printk('x'); + break; + case 0x2E: + printk('c'); + break; + case 0x2F: + printk('v'); + break; + case 0x30: + printk('b'); + break; + case 0x31: + printk('n'); + break; + case 0x32: + printk('m'); + break; + case 0x33: + printk(','); + break; + case 0x34: + printk('.'); + break; + case 0x35: + printk('/'); + break; + + case 0x1C: + printk('\n'); + break; + case 0x39: + printk(' '); + break; + + default: + printk("keyboard interrupt: ", uhex{key}, "\n"); + break; + } + } +} diff --git a/drivers/keyboard.h b/drivers/keyboard.h new file mode 100644 index 0000000..a14c2c0 --- /dev/null +++ b/drivers/keyboard.h @@ -0,0 +1,15 @@ +#pragma once + +#include "idt.h" +#include "ports.h" + +class Keyboard : public InterruptHandler { +public: + Keyboard(); + + void trigger() override; + +private: + keyboard_comm_t commandport; + keyboard_data_t dataport; +}; diff --git a/drivers/makefile b/drivers/makefile index ad255c4..2a1fa0c 100644 --- a/drivers/makefile +++ b/drivers/makefile @@ -1,5 +1,6 @@ CXX_OBJ += drivers/cga.o \ - drivers/serial.o + drivers/serial.o \ + drivers/keyboard.o HWH := drivers/hardware.h autogen := $(autogen) $(HWH) diff --git a/drivers/ports.h b/drivers/ports.h index f241299..2d26e65 100644 --- a/drivers/ports.h +++ b/drivers/ports.h @@ -58,4 +58,6 @@ typedef Port<0x2e8, uint8_t> com4_port_t; typedef Port<0x20, uint8_t> pic1_t; typedef Port<0xa0, uint8_t> pic2_t; -typedef Port<0x60, uint8_t> kb_t; +/* PS/2 keyboard */ +typedef Port<0x60, uint8_t> keyboard_data_t; +typedef Port<0x64, uint8_t> keyboard_comm_t; diff --git a/src/idt.cc b/src/idt.cc index fefe53e..68ae260 100644 --- a/src/idt.cc +++ b/src/idt.cc @@ -4,7 +4,23 @@ #include "ports.h" static_assert(sizeof(IDT::Pointer) == 6); -static_assert(sizeof(IDT::Entry) == 8); // size of IDT::Entry in protected mode is 64 bits + +static InterruptHandler* handlers[256] = {nullptr}; + +bool IDT::install(uint8_t irq, InterruptHandler* h) { + if (h != nullptr && handlers[irq] == nullptr) { + handlers[irq] = h; + return true; + } + return false; +} +bool IDT::uninstall(uint8_t irq, InterruptHandler* h) { + if (handlers[irq] == h) { + handlers[irq] = nullptr; + return true; + } + return false; +} /* reinitialize the PIC controllers, giving them specified vector offsets rather than 8h and 70h, as configured by default */ @@ -22,7 +38,10 @@ static_assert(sizeof(IDT::Entry) == 8); // size of IDT::Entry in protected mode #define ICW4_SFNM 0x10 /* Special fully nested (not) */ extern "C" uint32_t handle_interrupt(uint8_t irq, uint32_t esp) { - printk("interrupt ", uhex{irq}, '\n'); + if (handlers[irq] != nullptr) { + handlers[irq]->trigger(); + } + pic1_t pic1; pic1.write(0x20); if (irq > 7) { @@ -91,7 +110,6 @@ IDT::IDT(const uint16_t selector) { Pointer ptr{.limit = sizeof(table), .base = reinterpret_cast(table)}; asm volatile("lidt %0" : : "m"(ptr)); - asm volatile("sti"); printk("IDT installed at ", uhex{ptr.base}, '\n'); } diff --git a/src/idt.h b/src/idt.h index bc71f05..3a9848f 100644 --- a/src/idt.h +++ b/src/idt.h @@ -2,7 +2,21 @@ #include +class InterruptHandler { +private: + const uint8_t m_irq; + +protected: + InterruptHandler(uint8_t irq); + ~InterruptHandler(); + +public: + virtual void trigger(); +}; + class IDT { + friend class InterruptHandler; + public: struct Pointer { uint16_t limit; @@ -19,24 +33,23 @@ public: class Entry { public: constexpr Entry() = default; - Entry(void (*handler)(), uint16_t select, InterruptType t) { - offset_0_15 = reinterpret_cast(handler) & 0xffff; - offset_16_31 = (reinterpret_cast(handler) >> 16) & 0xffff; - selector = select; - type = t; - } + Entry(void (*handler)(), uint16_t select, InterruptType t); private: uint16_t offset_0_15 = 0; // 0-15 offset in the segment uint16_t selector = 0; // 16-31 selector of the code segment [[maybe_unused]] uint8_t null = 0; // 32-39 unused in protected mode InterruptType type = Null; // 40-43 type - uint16_t offset_16_31 = 0; // 48-63 offset high + uint16_t offset_16_31 = 0; // 48-63 offset high } __attribute__((packed)); IDT(const uint16_t selector); + void enable() { asm volatile("sti"); } private: Entry table[256]; + + static bool install(uint8_t, InterruptHandler*); + static bool uninstall(uint8_t, InterruptHandler*); }; diff --git a/src/idt/interruptgate.cc b/src/idt/interruptgate.cc new file mode 100644 index 0000000..0dbcce2 --- /dev/null +++ b/src/idt/interruptgate.cc @@ -0,0 +1,10 @@ +#include "../idt.h" + +static_assert(sizeof(IDT::Entry) == 8); // size of IDT::Entry in protected mode is 64 bits + +IDT::Entry::Entry(void (*handler)(), uint16_t select, IDT::InterruptType t) { + offset_0_15 = reinterpret_cast(handler) & 0xffff; + offset_16_31 = (reinterpret_cast(handler) >> 16) & 0xffff; + selector = select; + type = t; +} diff --git a/src/idt/interrupthandler.cc b/src/idt/interrupthandler.cc new file mode 100644 index 0000000..7af830b --- /dev/null +++ b/src/idt/interrupthandler.cc @@ -0,0 +1,14 @@ +#include +#include "../idt.h" + +InterruptHandler::InterruptHandler(uint8_t irq) : m_irq(irq) { + IDT::install(m_irq, this); +} + +InterruptHandler::~InterruptHandler() { + IDT::uninstall(m_irq, this); +} + +void InterruptHandler::trigger() { + printk("Unhandled interrupt ", uhex{m_irq}, '\n'); +} diff --git a/src/kernel.cc b/src/kernel.cc index 6bfb021..ff8e6bd 100644 --- a/src/kernel.cc +++ b/src/kernel.cc @@ -15,6 +15,8 @@ #include "idt.h" #include "serial.h" +#include "keyboard.h" + #include "hardware.h" typedef void (*constructor)(); @@ -48,6 +50,10 @@ void kernel_main([[maybe_unused]] uint32_t mb_magic, [[maybe_unused]] uint32_t m GDT gdt; IDT idt{gdt.codeDescriptor()}; + Keyboard kb; + + idt.enable(); + while (true) asm volatile("hlt"); } } // extern "C" diff --git a/src/makefile b/src/makefile index 8b21640..dda24af 100644 --- a/src/makefile +++ b/src/makefile @@ -7,7 +7,8 @@ CXX_OBJ += src/kernel.o \ src/memory.o \ src/gdt.o \ src/gdt/segmentdescriptor.o \ - src/idt.o + src/idt.o \ + src/idt/interruptgate.o src/idt/interrupthandler.o src/cpu/irq.h: $(OBJ_DIR)/src/cpu/exceptions.o $(OBJ_DIR)/src/cpu/interrupts.o @echo " GEN $@" diff --git a/toolchain.makefile b/toolchain.makefile index ee9cc0e..7a64904 100644 --- a/toolchain.makefile +++ b/toolchain.makefile @@ -15,7 +15,7 @@ CXX_FLAGS := -std=c++20 \ -Werror=shadow-all \ -Wold-style-cast -Wconversion \ -Wconsumed -CXX_INCLUDE := $(CURDIR)/libk $(CURDIR)/drivers +CXX_INCLUDE := $(CURDIR)/libk $(CURDIR)/src $(CURDIR)/drivers CXX_SYSTEM_INCLUDE := $(CURDIR)/grub # -- cgit v1.2.1