From: tadryanom_bot Date: Tue, 3 Feb 2026 02:39:32 +0000 (+0000) Subject: Feat: Add Shell, Keyboard Driver and Utils (LibC) X-Git-Url: https://projects.tadryanom.me/?a=commitdiff_plain;h=dd994f9d3c82f916b40b54e5b51aa56b93a4ce9e;p=AdrOS.git Feat: Add Shell, Keyboard Driver and Utils (LibC) --- diff --git a/include/keyboard.h b/include/keyboard.h new file mode 100644 index 0000000..bf61554 --- /dev/null +++ b/include/keyboard.h @@ -0,0 +1,12 @@ +#ifndef KEYBOARD_H +#define KEYBOARD_H + +#include + +// Callback function type: called when a char is decoded +typedef void (*keyboard_callback_t)(char); + +void keyboard_init(void); +void keyboard_set_callback(keyboard_callback_t callback); + +#endif diff --git a/include/shell.h b/include/shell.h new file mode 100644 index 0000000..2af8086 --- /dev/null +++ b/include/shell.h @@ -0,0 +1,6 @@ +#ifndef SHELL_H +#define SHELL_H + +void shell_init(void); + +#endif diff --git a/include/utils.h b/include/utils.h new file mode 100644 index 0000000..0305e06 --- /dev/null +++ b/include/utils.h @@ -0,0 +1,18 @@ +#ifndef UTILS_H +#define UTILS_H + +#include +#include + +size_t strlen(const char* str); +int strcmp(const char* s1, const char* s2); +int strncmp(const char* s1, const char* s2, size_t n); +void* memset(void* ptr, int value, size_t num); +void* memcpy(void* dst, const void* src, size_t n); + +// Reverse a string (helper for itoa) +void reverse(char* str, int length); +// Integer to ASCII +void itoa(int num, char* str, int base); + +#endif diff --git a/src/drivers/keyboard.c b/src/drivers/keyboard.c new file mode 100644 index 0000000..dbb5227 --- /dev/null +++ b/src/drivers/keyboard.c @@ -0,0 +1,78 @@ +#include "keyboard.h" +#include "idt.h" +#include "io.h" +#include "uart_console.h" +#include + +static keyboard_callback_t active_callback = NULL; + +// US QWERTY Map (Scancodes 0x00 - 0x39) +// 0 means unmapped or special key +static char scancode_map[128] = { + 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', /* Backspace */ + '\t', /* Tab */ + 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', /* Enter key */ + 0, /* 29 - Control */ + 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0, /* Left shift */ + '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, /* Right shift */ + '*', + 0, /* Alt */ + ' ', /* Space bar */ + 0, /* Caps lock */ + 0, /* 59 - F1 key ... > */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, /* < ... F10 */ + 0, /* 69 - Num lock*/ + 0, /* Scroll Lock */ + 0, /* Home key */ + 0, /* Up Arrow */ + 0, /* Page Up */ + -1, /* Minus */ + 0, /* Left Arrow */ + 0, + 0, /* Right Arrow */ + '+', + 0, /* 79 - End key*/ + 0, /* Down Arrow */ + 0, /* Page Down */ + 0, /* Insert Key */ + 0, /* Delete Key */ + 0, 0, 0, + 0, /* F11 Key */ + 0, /* F12 Key */ + 0, /* All other keys are undefined */ +}; + +void keyboard_handler_impl(struct registers* regs) { + (void)regs; + + // Read status + uint8_t status = inb(0x64); + + // Check if buffer is full + if (status & 0x01) { + uint8_t scancode = inb(0x60); + + // If highest bit set, it's a key release + if (scancode & 0x80) { + // TODO: Handle shift release + } else { + // Key Press + if (scancode < 128) { + char c = scancode_map[scancode]; + if (c != 0 && active_callback) { + active_callback(c); + } + } + } + } +} + +void keyboard_init(void) { + uart_print("[KBD] Initializing Keyboard Driver...\n"); + register_interrupt_handler(33, keyboard_handler_impl); +} + +void keyboard_set_callback(keyboard_callback_t callback) { + active_callback = callback; +} diff --git a/src/kernel/main.c b/src/kernel/main.c index 98546c3..e430184 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -6,42 +6,14 @@ #include "idt.h" #include "io.h" #include "process.h" +#include "keyboard.h" +#include "shell.h" /* Check if the compiler thinks we are targeting the wrong operating system. */ #if defined(__linux__) #error "You are not using a cross-compiler, you will run into trouble" #endif -// Simple Keyboard Handler Stub -void keyboard_handler(struct registers* regs) { - (void)regs; - // Read scan code from port 0x60 - uint8_t scancode = inb(0x60); - - // If top bit is set, it's a key release. Ignore. - if (!(scancode & 0x80)) { - uart_print("[KEY] Pressed!\n"); - } -} - -void task_a(void) { - uart_print("Task A Started!\n"); - for(;;) { - uart_print("A"); - for(volatile int i=0; i<5000000; i++); - schedule(); - } -} - -void task_b(void) { - uart_print("Task B Started!\n"); - for(;;) { - uart_print("B"); - for(volatile int i=0; i<5000000; i++); - schedule(); - } -} - /* * Kernel Entry Point * Arguments are passed from boot.S (architecture specific) @@ -79,29 +51,35 @@ void kernel_main(unsigned long magic, unsigned long addr) { uart_print("[AdrOS] Initializing IDT...\n"); idt_init(); - register_interrupt_handler(33, keyboard_handler); + // 5. Initialize Drivers + keyboard_init(); - // 5. Initialize Multitasking + // 6. Initialize Multitasking (Optional for Shell, but good to have) uart_print("[AdrOS] Initializing Scheduler...\n"); process_init(); - process_create_kernel(task_a); - process_create_kernel(task_b); + // Start Shell as the main interaction loop + shell_init(); #else uart_print("[WARN] VMM/IDT/Sched not implemented for this architecture yet.\n"); #endif uart_print("Welcome to AdrOS (x86/ARM/RISC-V/MIPS)!\n"); - uart_print("System Halted. Starting Multitasking...\n"); // Infinite loop acting as Idle Task + // Shell is interrupt driven, so we just idle here. for(;;) { - // uart_print("."); - schedule(); - + // We can execute background tasks here if needed #if defined(__i386__) || defined(__x86_64__) __asm__("hlt"); + #elif defined(__aarch64__) + __asm__("wfi"); + #elif defined(__riscv) + __asm__("wfi"); #endif + + // If we had preemptive scheduling, the timer would wake us up. + // For cooperative, we assume shell is ISR based so HLT is fine. } } diff --git a/src/kernel/shell.c b/src/kernel/shell.c new file mode 100644 index 0000000..e55d07d --- /dev/null +++ b/src/kernel/shell.c @@ -0,0 +1,96 @@ +#include "shell.h" +#include "keyboard.h" +#include "uart_console.h" +#include "utils.h" +#include "pmm.h" +#include "vga_console.h" + +#define MAX_CMD_LEN 256 +static char cmd_buffer[MAX_CMD_LEN]; +static int cmd_index = 0; + +void print_prompt(void) { + uart_print("\nAdrOS $> "); +} + +void execute_command(char* cmd) { + uart_print("\n"); + + if (strcmp(cmd, "help") == 0) { + uart_print("Available commands:\n"); + uart_print(" help - Show this list\n"); + uart_print(" clear - Clear screen (if VGA)\n"); + uart_print(" mem - Show memory stats\n"); + uart_print(" panic - Trigger kernel panic\n"); + uart_print(" reboot - Restart system\n"); + } + else if (strcmp(cmd, "clear") == 0) { + // ANSI clear screen for UART + uart_print("\033[2J\033[1;1H"); + + // TODO: Clear VGA if active + // vga_clear(); + } + else if (strcmp(cmd, "mem") == 0) { + // pmm_print_stats() is not impl yet, so let's fake it or add it + uart_print("Memory Stats:\n"); + uart_print(" Total RAM: [TODO] MB\n"); + uart_print(" Used: [TODO] KB\n"); + uart_print(" Free: [TODO] KB\n"); + } + else if (strcmp(cmd, "panic") == 0) { + // Trigger Int 0 (Div by zero) + int a = 1; + int b = 0; + int c = a / b; + (void)c; + } + else if (strcmp(cmd, "reboot") == 0) { + // 8042 keyboard controller reset command + uint8_t good = 0x02; + while (good & 0x02) + good = inb(0x64); + outb(0x64, 0xFE); + + // Triple Fault fallback + // idt_set_gate(0, 0, 0, 0); + // __asm__("int $0"); + } + else if (strlen(cmd) > 0) { + uart_print("Unknown command: "); + uart_print(cmd); + uart_print("\n"); + } + + print_prompt(); +} + +void shell_callback(char c) { + // Echo to screen + char str[2] = { c, 0 }; + + if (c == '\n') { + cmd_buffer[cmd_index] = 0; // Null terminate + execute_command(cmd_buffer); + cmd_index = 0; + } + else if (c == '\b') { + if (cmd_index > 0) { + cmd_index--; + uart_print("\b \b"); // Backspace hack + } + } + else { + if (cmd_index < MAX_CMD_LEN - 1) { + cmd_buffer[cmd_index++] = c; + uart_print(str); + } + } +} + +void shell_init(void) { + uart_print("[SHELL] Starting Shell...\n"); + cmd_index = 0; + keyboard_set_callback(shell_callback); + print_prompt(); +} diff --git a/src/kernel/utils.c b/src/kernel/utils.c new file mode 100644 index 0000000..3abcfdb --- /dev/null +++ b/src/kernel/utils.c @@ -0,0 +1,81 @@ +#include "utils.h" + +size_t strlen(const char* str) { + size_t len = 0; + while (str[len]) + len++; + return len; +} + +int strcmp(const char* s1, const char* s2) { + while (*s1 && (*s1 == *s2)) { + s1++; + s2++; + } + return *(const unsigned char*)s1 - *(const unsigned char*)s2; +} + +int strncmp(const char* s1, const char* s2, size_t n) { + while (n && *s1 && (*s1 == *s2)) { + s1++; + s2++; + n--; + } + if (n == 0) return 0; + return *(const unsigned char*)s1 - *(const unsigned char*)s2; +} + +void* memset(void* ptr, int value, size_t num) { + unsigned char* p = ptr; + while (num--) + *p++ = (unsigned char)value; + return ptr; +} + +void* memcpy(void* dst, const void* src, size_t n) { + char* d = dst; + const char* s = src; + while (n--) + *d++ = *s++; + return dst; +} + +void reverse(char* str, int length) { + int start = 0; + int end = length - 1; + while (start < end) { + char temp = str[start]; + str[start] = str[end]; + str[end] = temp; + start++; + end--; + } +} + +void itoa(int num, char* str, int base) { + int i = 0; + int isNegative = 0; + + if (num == 0) { + str[i++] = '0'; + str[i] = '\0'; + return; + } + + if (num < 0 && base == 10) { + isNegative = 1; + num = -num; + } + + while (num != 0) { + int rem = num % base; + str[i++] = (rem > 9) ? (rem - 10) + 'a' : rem + '0'; + num = num / base; + } + + if (isNegative) + str[i++] = '-'; + + str[i] = '\0'; + reverse(str, i); +}