diff options
Diffstat (limited to 'kernel/source/interrupts.cpp')
-rw-r--r-- | kernel/source/interrupts.cpp | 152 |
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; + } + +} |