aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAqua-sama <aqua@iserlohn-fortress.net>2021-02-28 22:39:25 +0200
committerAqua-sama <aqua@iserlohn-fortress.net>2021-02-28 22:39:25 +0200
commitae4265ea5d77b68757af39d73fe47df1a3563b42 (patch)
tree7282e3d43c471b195bb5a4742ed911c7b7626dcb
parentFix interrupts causing exception 0xd (diff)
downloadkernel.cpp-ae4265ea5d77b68757af39d73fe47df1a3563b42.tar.xz
Add keyboard driver
-rw-r--r--drivers/keyboard.cc147
-rw-r--r--drivers/keyboard.h15
-rw-r--r--drivers/makefile3
-rw-r--r--drivers/ports.h4
-rw-r--r--src/idt.cc24
-rw-r--r--src/idt.h27
-rw-r--r--src/idt/interruptgate.cc10
-rw-r--r--src/idt/interrupthandler.cc14
-rw-r--r--src/kernel.cc6
-rw-r--r--src/makefile3
-rw-r--r--toolchain.makefile2
11 files changed, 241 insertions, 14 deletions
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 <stdlib.h>
+
+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<uint32_t>(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 <types.h>
+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<uint32_t>(handler) & 0xffff;
- offset_16_31 = (reinterpret_cast<uint32_t>(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<uint32_t>(handler) & 0xffff;
+ offset_16_31 = (reinterpret_cast<uint32_t>(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 <stdlib.h>
+#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
#