summaryrefslogtreecommitdiff
path: root/kernel/source/interrupts.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/source/interrupts.cpp')
-rw-r--r--kernel/source/interrupts.cpp152
1 files changed, 152 insertions, 0 deletions
diff --git a/kernel/source/interrupts.cpp b/kernel/source/interrupts.cpp
new file mode 100644
index 0000000..6e22121
--- /dev/null
+++ b/kernel/source/interrupts.cpp
@@ -0,0 +1,152 @@
+#include <hilbert/kernel/input.hpp>
+#include <hilbert/kernel/panic.hpp>
+
+using namespace hilbert::kernel;
+
+struct [[gnu::packed]] exception_info_t {
+
+ uint64_t rax;
+ uint64_t rbx;
+ uint64_t rcx;
+ uint64_t rdx;
+ uint64_t rdi;
+ uint64_t rsi;
+ uint64_t rbp;
+ uint64_t rsp;
+ uint64_t r8;
+ uint64_t r9;
+ uint64_t r10;
+ uint64_t r11;
+ uint64_t r12;
+ uint64_t r13;
+ uint64_t r14;
+ uint64_t r15;
+
+ uint64_t cr2;
+ uint64_t cr3;
+ uint64_t rip;
+ uint64_t rflags;
+
+ uint64_t error;
+ uint8_t has_error;//0 or 1
+ uint8_t exception_number;
+
+};
+
+extern exception_info_t exception_info;
+
+extern "C" [[noreturn]] void print_exception() {
+
+ //so exception_info's type is known by gdb
+ exception_info_t the_exception_info = exception_info;
+ (void)the_exception_info;
+
+ //TODO: log exception, and recover if possible.
+
+ panic(0xba40bb);
+
+}
+
+static uint32_t current_flags = 0;
+
+#define SETBIT(field, bit, cond) \
+ field = (cond) ? (field | (bit)) : (field & ~(bit));
+
+static void got_key(uint32_t key) {
+
+ input::key_queue->insert(current_flags | key);
+ input::got_input();
+
+ if (key == (input::BREAK | 0x77))
+ current_flags ^= input::NUM_LOCK;
+
+ else if (key == (input::BREAK | 0x58))
+ current_flags ^= input::CAPS_LOCK;
+
+ else if ((key & 0xff) == 0xa7)
+ SETBIT(current_flags, input::RIGHT_WIN, !(key & input::BREAK))
+
+ else if ((key & 0xff) == 0x9f)
+ SETBIT(current_flags, input::LEFT_WIN, !(key & input::BREAK))
+
+ else if ((key & 0xff) == 0x91)
+ SETBIT(current_flags, input::RIGHT_ALT, !(key & input::BREAK))
+
+ else if ((key & 0xff) == 0x11)
+ SETBIT(current_flags, input::LEFT_ALT, !(key & input::BREAK))
+
+ else if ((key & 0xff) == 0x94)
+ SETBIT(current_flags, input::RIGHT_CTRL, !(key & input::BREAK))
+
+ else if ((key & 0xff) == 0x14)
+ SETBIT(current_flags, input::LEFT_CTRL, !(key & input::BREAK))
+
+ else if ((key & 0xff) == 0x59)
+ SETBIT(current_flags, input::RIGHT_SHIFT, !(key & input::BREAK))
+
+ else if ((key & 0xff) == 0x12)
+ SETBIT(current_flags, input::LEFT_SHIFT, !(key & input::BREAK))
+
+}
+
+static uint8_t key_so_far[8];
+uint8_t key_so_far_len = 0;
+
+extern "C" void on_keyboard_interrupt(uint8_t byte) {
+
+ key_so_far[key_so_far_len++] = byte;
+
+ if (key_so_far_len == 1) {
+ if (byte != 0xe0 && byte != 0xe1 && byte != 0xf0) {
+ got_key(byte);
+ key_so_far_len = 0;
+ }
+ }
+
+ else if (key_so_far_len == 2) {
+ if (key_so_far[0] == 0xe0 && byte != 0xf0 && byte != 0x12) {
+ got_key(byte | 0x80);
+ key_so_far_len = 0;
+ }
+ else if (key_so_far[0] == 0xf0) {
+ got_key(input::BREAK | byte);
+ key_so_far_len = 0;
+ }
+ }
+
+ else if (key_so_far_len == 3) {
+ if (key_so_far[0] == 0xe0 && key_so_far[1] == 0xf0 && byte != 0x7c) {
+ got_key(input::BREAK | byte | 0x80);
+ key_so_far_len = 0;
+ }
+ }
+
+ else if (key_so_far_len == 4) {
+ if (key_so_far[0] == 0xe0 && key_so_far[1] == 0x12 &&
+ key_so_far[2] == 0xe0 && byte == 0x7c) {
+ got_key(0xe0);
+ key_so_far_len = 0;
+ }
+ }
+
+ else if (key_so_far_len == 6) {
+ if (key_so_far[0] == 0xe0 && key_so_far[1] == 0xf0 &&
+ key_so_far[2] == 0x7c && key_so_far[3] == 0xe0 &&
+ key_so_far[4] == 0xf0 && byte == 0x12) {
+ got_key(input::BREAK | 0xe0);
+ key_so_far_len = 0;
+ }
+ }
+
+ else if (key_so_far_len == 8) {
+ if (key_so_far[0] == 0xe1 && key_so_far[1] == 0x14 &&
+ key_so_far[2] == 0x77 && key_so_far[3] == 0xe1 &&
+ key_so_far[2] == 0xf0 && key_so_far[3] == 0x14 &&
+ key_so_far[4] == 0xf0 && byte == 0x77) {
+ got_key(0xe1);
+ got_key(input::BREAK | 0xe1);
+ }
+ key_so_far_len = 0;
+ }
+
+}