This repository has been archived on 2025-02-26. You can view files and clone it, but cannot push or open issues or pull requests.
hilbert-os/kernel/source/interrupts.cpp

152 lines
3.5 KiB
C++

#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;
}
}