keyboard input

This commit is contained in:
Benji Dial 2024-01-27 23:14:29 -05:00
parent 7199e74aa2
commit a8a80d326d
19 changed files with 459 additions and 46 deletions

View file

@ -15,7 +15,7 @@ int main(int, char **) {
daguerre::image<daguerre::color24> img;
std::FILE *file = std::fopen("/assets/burdon.ppm", "r");
std::FILE *file = std::fopen("/init/burdon.ppm", "r");
assert(file != 0);
assert(daguerre::try_load_ppm(file, img));
std::fclose(file);
@ -30,6 +30,21 @@ int main(int, char **) {
daguerre::copy_image(img, fb, 0, 0, x_off, y_off, width, height);
while (true) {
uint32_t kp = _syscall_read_key_packet();
if ((kp & 0x0400ff) == 0x04005a) {
for (unsigned y = 0; y < img.get_height(); ++y)
for (unsigned x = 0; x < img.get_width(); ++x) {
img.get(x, y).r = ~img.get(x, y).r;
img.get(x, y).g = ~img.get(x, y).g;
img.get(x, y).b = ~img.get(x, y).b;
}
daguerre::copy_image(img, fb, 0, 0, x_off, y_off, width, height);
}
}
return 0;
}

78
documentation/keys.txt Normal file
View file

@ -0,0 +1,78 @@
a key packet, as returned by the kernel, is a 32-bit value. the top
13 bits are currently reserved. the next 11 bits are flags as follows:
0x040000: break (as opposed to make)
0x020000: num lock is on
0x010000: caps lock is on
0x008000: right windows
0x004000: left windows
0x002000: right alt
0x001000: left alt
0x000800: right ctrl
0x000400: left ctrl
0x000200: right shift
0x000100: left shift
the bottom 8 bits represent the key. for us qwerty, they are:
0x00: reserved | 0x40: reserved | 0x80: reserved | 0xc0: reserved
0x01: f9 | 0x41: , / < | 0x81: reserved | 0xc1: reserved
0x02: reserved | 0x42: k / K | 0x82: reserved | 0xc2: reserved
0x03: f5 | 0x43: i / I | 0x83: reserved | 0xc3: reserved
0x04: f3 | 0x44: o / O | 0x84: reserved | 0xc4: reserved
0x05: f1 | 0x45: 0 / ) | 0x85: reserved | 0xc5: reserved
0x06: f2 | 0x46: 9 / ( | 0x86: reserved | 0xc6: reserved
0x07: f12 | 0x47: reserved | 0x87: f7 | 0xc7: reserved
0x08: reserved | 0x48: reserved | 0x88: reserved | 0xc8: reserved
0x09: f10 | 0x49: . / > | 0x89: reserved | 0xc9: reserved
0x0a: f8 | 0x4a: / / ? | 0x8a: reserved | 0xca: numpad /
0x0b: f6 | 0x4b: l / L | 0x8b: reserved | 0xcb: reserved
0x0c: f4 | 0x4c: ; / : | 0x8c: reserved | 0xcc: reserved
0x0d: tab | 0x4d: p / P | 0x8d: reserved | 0xcd: reserved
0x0e: ` / ~ | 0x4e: - / _ | 0x8e: reserved | 0xce: reserved
0x0f: reserved | 0x4f: reserved | 0x8f: reserved | 0xcf: reserved
0x10: reserved | 0x50: reserved | 0x90: reserved | 0xd0: reserved
0x11: left alt | 0x51: reserved | 0x91: right alt | 0xd1: reserved
0x12: left shift | 0x52: ' / " | 0x92: | 0xd2: reserved
0x13: reserved | 0x53: reserved | 0x93: reserved | 0xd3: reserved
0x14: left ctrl | 0x54: [ / { | 0x94: right ctrl | 0xd4: reserved
0x15: q / Q | 0x55: = / + | 0x95: reserved | 0xd5: reserved
0x16: 1 / ! | 0x56: reserved | 0x96: reserved | 0xd6: reserved
0x17: reserved | 0x57: reserved | 0x97: reserved | 0xd7: reserved
0x18: reserved | 0x58: caps lock | 0x98: reserved | 0xd8: reserved
0x19: reserved | 0x59: right shift | 0x99: reserved | 0xd9: reserved
0x1a: z / Z | 0x5a: enter | 0x9a: reserved | 0xda: numpad enter
0x1b: s / S | 0x5b: ] / } | 0x9b: reserved | 0xdb: reserved
0x1c: a / A | 0x5c: reserved | 0x9c: reserved | 0xdc: reserved
0x1d: w / W | 0x5d: \ / | | 0x9d: reserved | 0xdd: reserved
0x1e: 2 / @ | 0x5e: reserved | 0x9e: reserved | 0xde: reserved
0x1f: reserved | 0x5f: reserved | 0x9f: left win | 0xdf: reserved
0x20: reserved | 0x60: reserved | 0xa0: reserved | 0xe0: print screen
0x21: c / C | 0x61: reserved | 0xa1: reserved | 0xe1: pause
0x22: x / X | 0x62: reserved | 0xa2: reserved | 0xe2: reserved
0x23: d / D | 0x63: reserved | 0xa3: reserved | 0xe3: reserved
0x24: e / E | 0x64: reserved | 0xa4: reserved | 0xe4: reserved
0x25: 4 / $ | 0x65: reserved | 0xa5: reserved | 0xe5: reserved
0x26: 3 / # | 0x66: backspace | 0xa6: reserved | 0xe6: reserved
0x27: reserved | 0x67: reserved | 0xa7: right win | 0xe7: reserved
0x28: reserved | 0x68: reserved | 0xa8: reserved | 0xe8: reserved
0x29: space | 0x69: numpad 1 | 0xa9: reserved | 0xe9: end
0x2a: v / V | 0x6a: reserved | 0xaa: reserved | 0xea: reserved
0x2b: f / F | 0x6b: numpad 4 | 0xab: reserved | 0xeb: cursor left
0x2c: t / T | 0x6c: numpad 7 | 0xac: reserved | 0xec: home
0x2d: r / R | 0x6d: reserved | 0xad: reserved | 0xed: reserved
0x2e: 5 / % | 0x6e: reserved | 0xae: reserved | 0xee: reserved
0x2f: reserved | 0x6f: reserved | 0xaf: menu | 0xef: reserved
0x30: reserved | 0x70: numpad 0 | 0xb0: reserved | 0xf0: insert
0x31: n / N | 0x71: numpad . | 0xb1: reserved | 0xf1: delete
0x32: b / B | 0x72: numpad 2 | 0xb2: reserved | 0xf2: cursor down
0x33: h / H | 0x73: numpad 5 | 0xb3: reserved | 0xf3: reserved
0x34: g / G | 0x74: numpad 6 | 0xb4: reserved | 0xf4: cursor right
0x35: y / Y | 0x75: numpad 8 | 0xb5: reserved | 0xf5: cursor up
0x36: 6 / ^ | 0x76: escape | 0xb6: reserved | 0xf6: reserved
0x37: reserved | 0x77: num lock | 0xb7: reserved | 0xf7: reserved
0x38: reserved | 0x78: f11 | 0xb8: reserved | 0xf8: reserved
0x39: reserved | 0x79: numpad + | 0xb9: reserved | 0xf9: reserved
0x3a: m / M | 0x7a: numpad 3 | 0xba: reserved | 0xfa: page down
0x3b: j / J | 0x7b: numpad - | 0xbb: reserved | 0xfb: reserved
0x3c: u / U | 0x7c: numpad * | 0xbc: reserved | 0xfc: reserved
0x3d: 7 / & | 0x7d: numpad 9 | 0xbd: reserved | 0xfd: page up
0x3e: 8 / * | 0x7e: scroll lock | 0xbe: reserved | 0xfe: reserved
0x3f: reserved | 0x7f: reserved | 0xbf: reserved | 0xff: reserved

View file

@ -66,3 +66,7 @@ get new pages:
close file:
rax in: 7
rdi in: file handle
read key packet:
rax in: 8
eax out: key packet

View file

@ -4,6 +4,8 @@
#include <hilbert/kernel/framebuffer.hpp>
#include <hilbert/kernel/terminal.hpp>
#include <hilbert/kernel/paging.hpp>
#include <hilbert/kernel/input.hpp>
#include <hilbert/kernel/panic.hpp>
#include <hilbert/kernel/vfile.hpp>
#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);

View file

@ -0,0 +1,26 @@
#pragma once
#include <hilbert/kernel/utility.hpp>
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<uint32_t> *key_queue;
//must be post switch to kernel page tables and mounting of file systems
void init_input();
}

View file

@ -0,0 +1,6 @@
#pragma once
namespace hilbert::kernel {
//prints to terminal and then halts.
[[noreturn]] void panic(const char *string_sz);
}

View file

@ -294,4 +294,54 @@ namespace hilbert::kernel::utility {
};
template <class value_t>
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);
}
};
}

View file

@ -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);
}

13
kernel/input.cpp Normal file
View file

@ -0,0 +1,13 @@
#include <hilbert/kernel/input.hpp>
#include <hilbert/kernel/panic.hpp>
#include <hilbert/kernel/vfile.hpp>
namespace hilbert::kernel::input {
utility::queue<uint32_t> *key_queue;
void init_input() {
key_queue = new utility::queue<uint32_t>();
}
}

View file

@ -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

View file

@ -1,4 +1,6 @@
#include <hilbert/kernel/terminal.hpp>
#include <hilbert/kernel/input.hpp>
#include <hilbert/kernel/panic.hpp>
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;
}
}

10
kernel/panic.cpp Normal file
View file

@ -0,0 +1,10 @@
#include <hilbert/kernel/terminal.hpp>
#include <hilbert/kernel/panic.hpp>
namespace hilbert::kernel {
[[noreturn]] void panic(const char *string_sz) {
terminal::put_string_sz(string_sz);
while (1)
asm ("hlt");
}
}

View file

@ -1,6 +1,7 @@
#include <hilbert/kernel/application.hpp>
#include <hilbert/kernel/framebuffer.hpp>
#include <hilbert/kernel/paging.hpp>
#include <hilbert/kernel/input.hpp>
#include <hilbert/kernel/vfile.hpp>
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;
}

View file

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

View file

@ -7,6 +7,7 @@ namespace euler::syscall {
typedef uint32_t encoded_color;
typedef int32_t exit_code;
typedef uint64_t file_handle;
typedef uint32_t key_packet;
enum [[nodiscard]] file_result : uint64_t {
success,
@ -45,4 +46,6 @@ extern "C" {
void _syscall_close_file(euler::syscall::file_handle file);
euler::syscall::key_packet _syscall_read_key_packet();
}

View file

@ -80,3 +80,9 @@ _syscall_close_file:
mov rax, 7
syscall
ret
global _syscall_read_key_packet
_syscall_read_key_packet:
mov rax, 8
syscall
ret

View file

@ -46,7 +46,7 @@ obj/kernel/%.asm.o: kernel/%.asm
KERNEL_OBJECTS = allocator.cpp application.cpp entry.cpp framebuffer.cpp \
paging.asm paging.cpp storage.cpp storage/bd/memory.cpp terminal.cpp \
storage/fs/tarfs.cpp utility.cpp vfile.cpp syscall.asm syscall.cpp \
interrupts.asm interrupts.cpp
interrupts.asm interrupts.cpp input.cpp panic.cpp
obj/kernel.elf: ${KERNEL_OBJECTS:%=obj/kernel/%.o}
ld ${KLD_ARGS} $^ -o $@