From a8a80d326de9550b2a25b1255a2093ab43219ede Mon Sep 17 00:00:00 2001 From: Benji Dial Date: Sat, 27 Jan 2024 23:14:29 -0500 Subject: keyboard input --- kernel/entry.cpp | 19 +++-- kernel/include/hilbert/kernel/input.hpp | 26 +++++++ kernel/include/hilbert/kernel/panic.hpp | 6 ++ kernel/include/hilbert/kernel/utility.hpp | 50 ++++++++++++++ kernel/include/hilbert/kernel/vfile.hpp | 8 +-- kernel/input.cpp | 13 ++++ kernel/interrupts.asm | 96 ++++++++++++++++++++++++-- kernel/interrupts.cpp | 111 +++++++++++++++++++++++++++++- kernel/panic.cpp | 10 +++ kernel/syscall.cpp | 44 ++++++------ kernel/vfile.cpp | 12 +++- 11 files changed, 351 insertions(+), 44 deletions(-) create mode 100644 kernel/include/hilbert/kernel/input.hpp create mode 100644 kernel/include/hilbert/kernel/panic.hpp create mode 100644 kernel/input.cpp create mode 100644 kernel/panic.cpp (limited to 'kernel') diff --git a/kernel/entry.cpp b/kernel/entry.cpp index 3a42df7..cc74e69 100644 --- a/kernel/entry.cpp +++ b/kernel/entry.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include "../limine/limine.h" @@ -184,12 +186,6 @@ extern "C" [[noreturn]] void entry() { } -[[noreturn]] static void print_and_halt(const char *msg) { - terminal::put_string_sz(msg); - while (1) - asm ("hlt"); -} - extern "C" [[noreturn]] void start_user_mode( uint64_t rip, uint64_t rsp, uint64_t p4_paddr); @@ -208,22 +204,25 @@ extern "C" [[noreturn]] void start_user_mode( if (initfs_fs->get_root_node(initfs_root.dir_entry.node) != storage::fs_result::success) - print_and_halt("failed to get root node of initfs."); + panic("failed to get root node of initfs."); vfile::set_root(initfs_root); + input::init_input(); + utility::string init_path_string("/bin/init.elf", 13); vfile::canon_path init_path; vfile::canonize_path(init_path_string, init_path); vfile::vfile init_file; - if (vfile::lookup_path(init_path, init_file) != storage::fs_result::success) - print_and_halt("failed to look up /bin/init.elf."); + if (vfile::lookup_path(init_path, init_file, true) != + storage::fs_result::success) + panic("failed to look up /bin/init.elf."); application::app_instance *init; if (application::create_app(init_file, init, initfs_root) != application::create_app_result::success) - print_and_halt("failed to parse /bin/init.elf."); + panic("failed to parse /bin/init.elf."); application::running_app = init; start_user_mode(init->saved_regs.rip, init->saved_regs.rsp, init->p4_paddr); diff --git a/kernel/include/hilbert/kernel/input.hpp b/kernel/include/hilbert/kernel/input.hpp new file mode 100644 index 0000000..cccb71f --- /dev/null +++ b/kernel/include/hilbert/kernel/input.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include + +namespace hilbert::kernel::input { + + enum : uint32_t { + LEFT_SHIFT = 1 << 8, + RIGHT_SHIFT = 1 << 9, + LEFT_CTRL = 1 << 10, + RIGHT_CTRL = 1 << 11, + LEFT_ALT = 1 << 12, + RIGHT_ALT = 1 << 13, + LEFT_WIN = 1 << 14, + RIGHT_WIN = 1 << 15, + CAPS_LOCK = 1 << 16, + NUM_LOCK = 1 << 17, + BREAK = 1 << 18, + }; + + extern utility::queue *key_queue; + + //must be post switch to kernel page tables and mounting of file systems + void init_input(); + +} diff --git a/kernel/include/hilbert/kernel/panic.hpp b/kernel/include/hilbert/kernel/panic.hpp new file mode 100644 index 0000000..545d703 --- /dev/null +++ b/kernel/include/hilbert/kernel/panic.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace hilbert::kernel { + //prints to terminal and then halts. + [[noreturn]] void panic(const char *string_sz); +} diff --git a/kernel/include/hilbert/kernel/utility.hpp b/kernel/include/hilbert/kernel/utility.hpp index 2df1d65..47f78ea 100644 --- a/kernel/include/hilbert/kernel/utility.hpp +++ b/kernel/include/hilbert/kernel/utility.hpp @@ -294,4 +294,54 @@ namespace hilbert::kernel::utility { }; + template + struct queue { + + value_t *buffer; + unsigned buffer_len; + unsigned count; + unsigned next_read_index; + + queue(unsigned initial_len = 1024) : buffer(new value_t[initial_len]), + buffer_len(initial_len), count(0), next_read_index(0) { } + + ~queue() { + delete[] buffer; + } + + void insert(const value_t &v) { + + if (count == buffer_len) { + value_t *new_buffer = new value_t[buffer_len * 2]; + for (unsigned i = 0; i < buffer_len - next_read_index; ++i) + new_buffer[i] = move(buffer[i + next_read_index]); + for (unsigned i = buffer_len - next_read_index; i < buffer_len; ++i) + new_buffer[i] = move(buffer[i + next_read_index - buffer_len]); + delete[] buffer; + buffer = new_buffer; + buffer_len *= 2; + next_read_index = 0; + } + + buffer[(count + next_read_index) % buffer_len] = v; + ++count; + + } + + //assumes not empty + const value_t &peek() const { + return buffer[next_read_index]; + } + + //assumes not empty + value_t &&take() { + value_t &&ret = move(buffer[next_read_index]); + if (++next_read_index == buffer_len) + next_read_index = 0; + --count; + return move(ret); + } + + }; + } diff --git a/kernel/include/hilbert/kernel/vfile.hpp b/kernel/include/hilbert/kernel/vfile.hpp index f8a387d..b64ae63 100644 --- a/kernel/include/hilbert/kernel/vfile.hpp +++ b/kernel/include/hilbert/kernel/vfile.hpp @@ -55,9 +55,9 @@ namespace hilbert::kernel::vfile { //TODO: see comment at top of file. void set_root(const vfile &root); - //path must be absolute. follows symlinks on all but the last node. - //relative_to should be a directory to do the lookup inside; e.g., - //if relative_to is /a/b and path is c, then out becomes /a/b/c. - storage::fs_result lookup_path(const canon_path &path, vfile &out); + //path must be absolute. follows symlinks on all but the last node + //always, and on the last node when follow_final_symlink is true. + storage::fs_result lookup_path( + const canon_path &path, vfile &out, bool follow_final_symlink); } diff --git a/kernel/input.cpp b/kernel/input.cpp new file mode 100644 index 0000000..6bed7f5 --- /dev/null +++ b/kernel/input.cpp @@ -0,0 +1,13 @@ +#include +#include +#include + +namespace hilbert::kernel::input { + + utility::queue *key_queue; + + void init_input() { + key_queue = new utility::queue(); + } + +} diff --git a/kernel/interrupts.asm b/kernel/interrupts.asm index 4827cfd..c096ddb 100644 --- a/kernel/interrupts.asm +++ b/kernel/interrupts.asm @@ -220,27 +220,111 @@ gdt: .tss: dq 0x0000e90000000067 dq 0;tss is 2 qwords wide - dq 0x00209b0000000000 - dq 0x00009b0000000000 - dq 0x0000fb0000000000 - dq 0x0020fb0000000000 + dq 0x002f98000000ffff + dq 0x002f92000000ffff + dq 0x002ff2000000ffff + dq 0x002ff8000000ffff + +section .bss section .text +write_keyboard_byte: + in al, 0x64 + test al, 0x02 + jnz write_keyboard_byte + mov al, dil + out 0x60, al + ret + +extern on_keyboard_interrupt + +keyboard_isr: + + push r11 + push r10 + push r9 + push r8 + push rsi + push rdi + push rdx + push rcx + push rax + + in al, 0x60 + mov dil, al + + call on_keyboard_interrupt + + mov al, 0x20 + out 0x20, al + + pop rax + pop rcx + pop rdx + pop rdi + pop rsi + pop r8 + pop r9 + pop r10 + pop r11 + + iretq + load_gdt_and_idt: + ;fill exception entries in idt + mov rcx, 16 .loop: mov rdi, rcx dec rdi - mov sil, 0 + mov sil, 1 mov rdx, qword [exception_isrs + rdi * 8] call set_isr loop .loop + ;reset pic and map irqs to 0x20 - 0x2f + + mov al, 0x11 + out 0x20, al + mov al, 0x20 + out 0x21, al + mov al, 0x04 + out 0x21, al + mov al, 0x01 + out 0x21, al + mov al, 0xfd ;mask all but irq 1 + out 0x21, al + + mov al, 0x11 + out 0xa0, al + mov al, 0x28 + out 0xa1, al + mov al, 0x02 + out 0xa1, al + mov al, 0x01 + out 0xa1, al + mov al, 0xff ;mask all + out 0xa1, al + + mov rdi, 0x21 + xor sil, sil + mov rdx, keyboard_isr + call set_isr + + ;set keyboard config + + mov al, 0x60 + out 0x64, al + mov dil, 0x01 + call write_keyboard_byte + + ;make tss entry in gdt + mov rax, tss mov word [gdt.tss + 2], ax @@ -250,6 +334,8 @@ load_gdt_and_idt: shr rax, 16 mov dword [gdt.tss + 8], eax + ;load gdt, idt, tss + lgdt [gdtr] lidt [idtr] mov ax, 0x18 diff --git a/kernel/interrupts.cpp b/kernel/interrupts.cpp index 1a95f22..cd57c4f 100644 --- a/kernel/interrupts.cpp +++ b/kernel/interrupts.cpp @@ -1,4 +1,6 @@ #include +#include +#include using namespace hilbert::kernel; @@ -34,7 +36,7 @@ struct [[gnu::packed]] exception_info_t { extern exception_info_t exception_info; -const char *exception_types[] = { +static const char *exception_types[] = { "division error", "", "non-maskable interrupt", @@ -53,7 +55,7 @@ const char *exception_types[] = { "" }; -const char *flag_names[] = { +static const char *flag_names[] = { " cf", "", " pf", @@ -72,7 +74,7 @@ const char *flag_names[] = { " md" }; -void print_line(const char *r1, const char *r2, uint64_t r1v, uint64_t r2v) { +static void print_line(const char *r1, const char *r2, uint64_t r1v, uint64_t r2v) { terminal::put_string_sz("\n "); terminal::put_string_sz(r1); terminal::put_string_sz(": 0x"); @@ -123,3 +125,106 @@ extern "C" [[noreturn]] void print_exception() { asm ("hlt"); } + +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); + + 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; + } + +} diff --git a/kernel/panic.cpp b/kernel/panic.cpp new file mode 100644 index 0000000..233fcf4 --- /dev/null +++ b/kernel/panic.cpp @@ -0,0 +1,10 @@ +#include +#include + +namespace hilbert::kernel { + [[noreturn]] void panic(const char *string_sz) { + terminal::put_string_sz(string_sz); + while (1) + asm ("hlt"); + } +} diff --git a/kernel/syscall.cpp b/kernel/syscall.cpp index 3c72d23..e194eb1 100644 --- a/kernel/syscall.cpp +++ b/kernel/syscall.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include namespace hilbert::kernel::syscall { @@ -82,7 +83,7 @@ namespace hilbert::kernel::syscall { set_zero(rax, rdi, rsi, rdx); vfile::vfile file; - switch (vfile::lookup_path(cp, file)) { + switch (vfile::lookup_path(cp, file, true)) { case storage::fs_result::success: break; case storage::fs_result::device_error: @@ -96,28 +97,13 @@ namespace hilbert::kernel::syscall { return; } - vfile::vfile real_file; - switch (file.follow_symlinks(real_file)) { - case storage::fs_result::success: - break; - case storage::fs_result::device_error: - rax = file_result_device_error; - return; - case storage::fs_result::fs_corrupt: - rax = file_result_file_system_corrupt; - return; - case storage::fs_result::does_not_exist: - rax = file_result_does_not_exist; - return; - } - - if (real_file.dir_entry.type != storage::file_type::regular_file) { + if (file.dir_entry.type != storage::file_type::regular_file) { rax = file_result_directory; return; } unsigned handler = - application::running_app->open_files.add_new(utility::move(real_file)); + application::running_app->open_files.add_new(utility::move(file)); rax = file_result_success; rdi = (uint64_t)handler; @@ -226,6 +212,23 @@ namespace hilbert::kernel::syscall { } + void read_key_packet_syscall( + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx + ) { + + set_zero(rax, rdi, rsi, rdx); + + asm ("cli"); + + while (input::key_queue->count == 0) + asm ("sti\nhlt\ncli"); + + rax = (uint64_t)input::key_queue->take(); + + asm ("sti"); + + } + typedef void (*syscall_handler)( uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx); @@ -237,10 +240,11 @@ namespace hilbert::kernel::syscall { &read_from_file_syscall, &end_this_process_syscall, &get_new_pages_syscall, - &close_file_syscall + &close_file_syscall, + &read_key_packet_syscall }; - static constexpr int max_syscall_number = 7; + static constexpr int max_syscall_number = 8; } diff --git a/kernel/vfile.cpp b/kernel/vfile.cpp index 028db6d..89c95e6 100644 --- a/kernel/vfile.cpp +++ b/kernel/vfile.cpp @@ -94,7 +94,7 @@ namespace hilbert::kernel::vfile { full_path.rel(target_path); vfile next; - RET_NOT_SUC(lookup_path(full_path, next)) + RET_NOT_SUC(lookup_path(full_path, next, false)) next.path = path; return next.follow_symlinks(out); @@ -175,7 +175,9 @@ namespace hilbert::kernel::vfile { kernel::vfile::root = new vfile(root); } - storage::fs_result lookup_path(const canon_path &path, vfile &out) { + storage::fs_result lookup_path( + const canon_path &path, vfile &out, bool follow_final_symlink + ) { //assume path is absolute. @@ -191,6 +193,12 @@ namespace hilbert::kernel::vfile { } + if (follow_final_symlink) { + vfile result; + RET_NOT_SUC(out.follow_symlinks(result)) + out = utility::move(result); + } + return storage::fs_result::success; } -- cgit v1.2.3