From 078ca8169bffe1160189b60f362f2b52d86313ee Mon Sep 17 00:00:00 2001 From: David Goeke Date: Thu, 3 Jul 2025 20:30:21 -0500 Subject: [PATCH] Espresso 0.0.1d --- drivers/irq.c | 45 +++++++++++-- drivers/ps2_keyboard.c | 114 ++++++++++++++++++++++++++++----- drivers/tty.c | 8 +++ include/builtin_games/miner.h | 8 +++ include/drivers/irq.h | 3 + include/drivers/ps2_keyboard.h | 10 +++ include/ksymtab.h | 6 ++ include/string.h | 4 +- include/tty.h | 2 + include/types.h | 7 ++ kernel/kernel.c | 13 ++-- ksymtab.s | 0 lib/builtin_games/miner.c | 76 ++++++++++++++++++++++ lib/ksymtab.c | 69 ++++++++++++++++++++ 14 files changed, 337 insertions(+), 28 deletions(-) create mode 100644 include/builtin_games/miner.h create mode 100644 include/ksymtab.h create mode 100644 ksymtab.s create mode 100644 lib/builtin_games/miner.c create mode 100644 lib/ksymtab.c diff --git a/drivers/irq.c b/drivers/irq.c index d1984dd..35d98ec 100644 --- a/drivers/irq.c +++ b/drivers/irq.c @@ -4,26 +4,63 @@ #include -irq_func_t func_list[64]; +#define NUM_IRQS 0x90 + +irq_func_t func_list[NUM_IRQS]; +irq_func_t aux_func_list[NUM_IRQS]; + +static volatile uint32_t num_irqs_missed = 0; void irq_init(void) { + memset(func_list, 0x0, NUM_IRQS); + memset(aux_func_list, 0x0, NUM_IRQS); + set_irq_handler(0, (irq_func_t*)pit_handler); set_irq_handler(1, (irq_func_t*)keyboard_handler); } void irq_handler(uint8_t irq_number) { - if (irq_number < 64 && func_list[irq_number]) + if (irq_number < NUM_IRQS) { - func_list[irq_number](); + if (func_list[irq_number]) + { + func_list[irq_number](); + } + else if (aux_func_list[irq_number]) + { + aux_func_list[irq_number](); + } + else + { + num_irqs_missed++; + } } } void set_irq_handler(uint32_t num, irq_func_t* handler) { - if (num < 64) + if (num < NUM_IRQS) { func_list[num] = (irq_func_t)handler; } } + +void add_irq_handler(uint32_t num, irq_func_t* handler) +{ + if (num < NUM_IRQS) + { + if (func_list[num] != 0x0) + { + if (aux_func_list[num] == 0x0) + { + aux_func_list[num] = (irq_func_t)handler; + } + + return; + } + + func_list[num] = (irq_func_t)handler; + } +} diff --git a/drivers/ps2_keyboard.c b/drivers/ps2_keyboard.c index bb7148f..ab52a2c 100644 --- a/drivers/ps2_keyboard.c +++ b/drivers/ps2_keyboard.c @@ -36,15 +36,22 @@ static bool shift_pressed = false; /* State for caps-lock key */ static bool capslock_pressed = false; -volatile char current_char; +/* Used for arrow keys among others */ +static bool extended = false; + +static bool is_new_char = false; +static bool is_new_key = false; + +volatile unsigned char current_char; volatile char* current_string = NULL; volatile int32_t current_length = 0; volatile int32_t capacity = 0; +volatile uint16_t current_key; static const char scancode_map[128] = { 0, 27, '1','2','3','4','5','6','7','8','9','0','-','=','\b', /* Backspace */ - '\t', // Tab + '\t', /* Tab */ 'q','w','e','r','t','y','u','i','o','p','[',']','\n', /* Enter */ 0, /* Control */ 'a','s','d','f','g','h','j','k','l',';','\'','`', @@ -67,7 +74,46 @@ void keyboard_init(void) char get_char(void) { - return current_char; + /* + ASCII code 5 (Enquiry) is/was used in legacy systems meant for requesting a response from a remote terminal or device. + For example, one system might send ENQ (ASCII 5), and the receiver could reply with ACK (ASCII 6) to indicate it’s ready or still online. + + In modern computing, ENQ is largely obsolete: + + - Terminal emulators, shells, operating systems, and network protocols generally do not use ENQ. + + - It's not used in text files, programming, or standard communications. + + - It may still appear in legacy systems, embedded devices, or proprietary serial protocols, but that's niche. + */ + char temp = 5; + + if (is_new_char) + { + temp = current_char; + } + + is_new_char = false; + + return temp; +} + +uint16_t get_key(void) +{ + uint16_t temp = 0xFFFA; + + if (is_new_key) + { + temp = current_key; + is_new_key = false; + } + else if (is_new_char) + { + temp = (uint16_t)current_char; + is_new_char = false; + } + + return temp; } char* get_string(void) @@ -118,7 +164,8 @@ static void free_current_string(void) } } -void keyboard_handler(void) { +void keyboard_handler(void) +{ uint8_t scancode = inb(PS2_DATA_PORT); /* Handle shift press/release */ @@ -137,41 +184,76 @@ void keyboard_handler(void) { capslock_pressed = !capslock_pressed; return; } + else if (scancode == 0xE0) + { + extended = true; + return; + } if (scancode & 0x80) { - /* Key release event, ignore for now */ - } else + extended = false; + } + else { - char c = scancode_map[scancode]; - if ((shift_pressed ^ capslock_pressed) && c >= 'a' && c <= 'z') { + uint16_t c = (uint16_t)scancode_map[scancode]; + if ((shift_pressed ^ capslock_pressed) && ((char)c >= 'a') && ((char)c <= 'z')) + { c -= 32; /* Convert to uppercase */ } else if (shift_pressed) { - c = (char) terminal_get_shifted((unsigned char) c); + c = (uint16_t) terminal_get_shifted((unsigned char) c); } - if (scancode == 0x1C) { + /*if (scancode == 0x1C) { printf("\n"); return; - } + }*/ + if (extended) + { + switch (scancode) + { + case 0x48: + c = KEY_ARROW_UP; + break; + case 0x50: + c = KEY_ARROW_DOWN; + break; + case 0x4B: + c = KEY_ARROW_LEFT; + break; + case 0x4D: + c = KEY_ARROW_RIGHT; + break; + default: + c = KEY_NONE; + break; + } + + current_key = c; + + is_new_key = true; + extended = false; + + return; + } + if (c) { current_char = c; + is_new_char = true; + if (c == '\n') { free_current_string(); } - else - { - append_char(c); - printf("%c", c); - } + + append_char(c); } } } diff --git a/drivers/tty.c b/drivers/tty.c index 6c9269f..7b74d1a 100644 --- a/drivers/tty.c +++ b/drivers/tty.c @@ -247,3 +247,11 @@ unsigned char terminal_get_shifted(unsigned char uc) return '\0'; } +void terminal_set_cursor(uint16_t row, uint16_t column) +{ + if (row < VGA_HEIGHT && column < VGA_WIDTH) + { + terminal_row = (size_t)row; + terminal_column = (size_t)column; + } +} diff --git a/include/builtin_games/miner.h b/include/builtin_games/miner.h new file mode 100644 index 0000000..7dc1966 --- /dev/null +++ b/include/builtin_games/miner.h @@ -0,0 +1,8 @@ +#ifndef _MINER_H +#define _MINER_H + +#include + +void miner_main(void); + +#endif diff --git a/include/drivers/irq.h b/include/drivers/irq.h index 631bd0a..13629a3 100644 --- a/include/drivers/irq.h +++ b/include/drivers/irq.h @@ -6,7 +6,10 @@ typedef void (*irq_func_t)(void); void irq_init(void); + void irq_handler(uint8_t irq_number); + void set_irq_handler(uint32_t num, irq_func_t* handler); +void add_irq_handler(uint32_t num, irq_func_t* handler); #endif diff --git a/include/drivers/ps2_keyboard.h b/include/drivers/ps2_keyboard.h index e043914..2d3cc0b 100644 --- a/include/drivers/ps2_keyboard.h +++ b/include/drivers/ps2_keyboard.h @@ -3,10 +3,20 @@ #include +typedef enum { + KEY_NONE = 0, + KEY_ARROW_UP = 0xAA0, + KEY_ARROW_DOWN, + KEY_ARROW_LEFT, + KEY_ARROW_RIGHT, + /* Note: add more special keys here */ +} special_key; + void keyboard_init(void); void keyboard_handler(void); char get_char(void); +uint16_t get_key(void); char* get_string(void); #endif diff --git a/include/ksymtab.h b/include/ksymtab.h new file mode 100644 index 0000000..3d26835 --- /dev/null +++ b/include/ksymtab.h @@ -0,0 +1,6 @@ +#ifndef _KSYMTAB_H +#define _KSYMTAB_H + +#include + +#endif diff --git a/include/string.h b/include/string.h index 6ff6041..0734181 100644 --- a/include/string.h +++ b/include/string.h @@ -24,8 +24,8 @@ char lower(char c); char toupper(char c); char lower(char c); -void *memset(void *dst, char c, uint32_t n); -void *memcpy(void *dst, const void *src, uint32_t n); +void* memset(void *dst, char c, uint32_t n); +void* memcpy(void *dst, const void *src, uint32_t n); int32_t memcmp(const void *s1, const void *s2, size_t n); void* memclr(void* m_start, size_t m_count); diff --git a/include/tty.h b/include/tty.h index 33d3f2f..8364a41 100644 --- a/include/tty.h +++ b/include/tty.h @@ -25,4 +25,6 @@ void terminal_scroll(void); unsigned char terminal_get_shifted(unsigned char uc); +void terminal_set_cursor(uint16_t row, uint16_t column); + #endif diff --git a/include/types.h b/include/types.h index 5f54e95..4b3a71f 100644 --- a/include/types.h +++ b/include/types.h @@ -5,4 +5,11 @@ #include #include +typedef unsigned char uchar; + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + #endif diff --git a/kernel/kernel.c b/kernel/kernel.c index 20dba25..d2ad74e 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -37,6 +37,8 @@ #include +#include + #define DEBUG @@ -44,12 +46,12 @@ extern void _hang_asm(void); extern void _sti_asm(void); -void kernel_main(multiboot_info_t* mbd, unsigned int magic) +void kernel_main(multiboot_info_t* mbd, uint32_t magic) { /* --- BEGIN INITIALIZATION SECTION --- */ - const char* espresso_kernel_version = "0.0.0f"; + const char* espresso_kernel_version = "0.0.1d"; /* We need to initialize the terminal so that any error/debugging messages show. */ terminal_initialize(); @@ -78,7 +80,7 @@ void kernel_main(multiboot_info_t* mbd, unsigned int magic) idt_init(); _sti_asm(); - irq_init(); /* MUST be done after pci_remap() and idt_init() */ + irq_init(); /* MUST be done after pic_remap() and idt_init() */ terminal_setcolor(VGA_COLOR_GREEN); @@ -132,7 +134,6 @@ void kernel_main(multiboot_info_t* mbd, unsigned int magic) printd("PCI initialized\n"); - /* --- END INITIALIZATION SECTION --- */ terminal_setcolor(VGA_COLOR_LIGHT_GREEN); @@ -141,14 +142,14 @@ void kernel_main(multiboot_info_t* mbd, unsigned int magic) /*pit_sleep(4000); begin_anim(espresso_kernel_version);*/ - printf("Guten tag and welcome to Espresso\n"); - /*printf("here\n"); printf("%i\n", sfs_init(false)); printf("here\n");*/ + printf("Guten tag and welcome to Espresso\n"); + while (true) { diff --git a/ksymtab.s b/ksymtab.s new file mode 100644 index 0000000..e69de29 diff --git a/lib/builtin_games/miner.c b/lib/builtin_games/miner.c new file mode 100644 index 0000000..5c3266b --- /dev/null +++ b/lib/builtin_games/miner.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include + +#include + + +#define PLAYER '@' +#define SHOP '$' +#define STONE '#' +#define IRON ';' +#define COAL ':' +#define COPPER '^' +#define GOLD '%' +#define RUBY '*' +#define DIAMOND '~' +#define PLATINUM '&' +#define NOTHING ' ' + + +/* + static const size_t VGA_WIDTH = 80; + static const size_t VGA_HEIGHT = 25; +*/ + + + +void miner_main(void) +{ + terminal_clear(); + + printf("\n\tMiner\n\t\tMine ores to sell for money and upgrade your drone\n\n\n\t\t\tHIT ENTER TO CONTINUE, TAB TO EXIT\n"); + + char b = get_char(); + + while (b != '\n' && b != '\t') + { + sleep(10); + b = get_char(); + } + + if (b == '\t') + { + return; + } + + uint16_t c = 0x0; + + terminal_clear(); + + while (true) + { + sleep(10); + + c = get_key(); + + if (c == 0xFFFA || c == 0x0) + { + continue; + } + + break; + } + + b = getchar(); + + while (b == 0x5) + { + sleep(10); + b = getchar(); + } + + terminal_clear(); +} diff --git a/lib/ksymtab.c b/lib/ksymtab.c new file mode 100644 index 0000000..735f26e --- /dev/null +++ b/lib/ksymtab.c @@ -0,0 +1,69 @@ + + +#include + +typedef struct kfunc { + /* + Bit 31 = 1 -> driver/module function, Bit 31 = 0 -> kernel function + Bits 30-20 -> module/driver ID (11 bits) + Bits 19-0 -> function ID (20 bits) + */ + uint32_t id; + + uint32_t addr; /* Pointer to function, 0x0 if nonexistent */ +} kfunc_t; + + +#define KFUNC_TABLE_ADDRESS 0xC0101000 +#define KFUNC_TABLE_SIZE (2 ^ 31) /* Maybe? who knows? */ + +#define IS_MODULE_FUNC(id) ((id) & 0x80000000) +#define GET_MODULE_ID(id) (((id) >> 20) & 0x7FF) +#define GET_FUNC_ID(id) ((id) & 0xFFFFF) +#define EXISTS(id) ((id) > 0x0) + +#define MAKE_KERNEL_FUNC(id) ((id) & 0x7FFFFFFF) + +#define MAKE_MODULE_FUNC(mid, fid) (0x80000000 | ((mid) << 20) | ((fid) & 0xFFFFF)) + + +kfunc_t* kfunc_table = (kfunc_t*)KFUNC_TABLE_ADDRESS; + + +uint64_t kfunc_call(kfunc_t* func, uint32_t a, uint32_t b, uint32_t c, uint32_t d) +{ + uint32_t eax_ret, edx_ret; + + asm volatile ( + "push %[d]\n\t" + "push %[c]\n\t" + "push %[b]\n\t" + "push %[a]\n\t" + "call *%[fn]\n\t" + "add $16, %%esp\n\t" /* clean up stack (4 args * 4 bytes) */ + : "=a"(eax_ret), "=d"(edx_ret) + : [a]"r"(a), [b]"r"(b), [c]"r"(c), [d]"r"(d), [fn]"r"(func->addr) + : "memory" + ); + + return ((uint64_t)edx_ret << 32) | eax_ret; +} + + + +uint64_t call_kfunc_by_id(uint32_t id, uint32_t a, uint32_t b, uint32_t c, uint32_t d) +{ + for (int i = 0; i < KFUNC_TABLE_SIZE; i++) + { + if (kfunc_table[i].id == id) + { + if (kfunc_table[i].addr == 0x0) + { + return -1; + } + return kfunc_call(&kfunc_table[i], a, b, c, d); + } + } + return -1; +} +