From fb27ad1e0c63d5c3e1f11f051f83d831a463a4fe Mon Sep 17 00:00:00 2001 From: AfonsoCMSousa Date: Mon, 3 Aug 2026 20:33:05 +0100 Subject: [PATCH] Feat: Starting of ACTUALL keyboard inturruptions with PIC --- boot/elevator.asm | 82 +++++++++++++- kernel.c | 14 +-- stdio.h | 281 +++++++++++++++++++++++++++------------------- 3 files changed, 254 insertions(+), 123 deletions(-) diff --git a/boot/elevator.asm b/boot/elevator.asm index 77d31d7..ded6c48 100644 --- a/boot/elevator.asm +++ b/boot/elevator.asm @@ -1,8 +1,6 @@ ; File: elevator.asm ; Stage 2 Bootloader - No size limit! ; Job: Load kernel, set up GDT, switch to 64-bit mode, jump to kernel - - [org 0x7e00] [bits 16] @@ -492,6 +490,7 @@ pm_msg: db '[PM32] Setting up Long Mode...', 0 ; 64-BIT LONG MODE ; ============================================================ [bits 64] +[extern __keyboard_buffer_push] ; External function to push key into keyboard buffer long_mode: ; Set up segments mov ax, 0x20 @@ -506,6 +505,9 @@ long_mode: ; Point all interrupts to a dummy handler call setup_idt + ; Set up PIC to avoid spurious interrupts + call setup_pics + ; Print message on line 3 mov rdi, 0xb8000 + (160 * 2) mov rsi, lm_msg @@ -516,6 +518,8 @@ long_mode: mov rsi, before_kernel_msg call print_64 + sti ; Enable interrupts before jumping to kernel + ; JUMP TO KERNEL! call KERNEL_OFFSET @@ -572,6 +576,80 @@ setup_idt: lidt [idt_descriptor] ret +setup_pics: + ; Loads master values into rdi/rsi/rdx/rcx + mov rdi, 0x20 ; Master command port + mov rsi, 0x21 ; Master data port + mov rdx, 0x20 ; Master offset + mov rcx, 0x04 ; Master ICW3 value + call setup_pic + + ; Loads slave values into rdi/rsi/rdx/rcx + mov rdi, 0xA0 ; Slave command port + mov rsi, 0xA1 ; Slave data port + mov rdx, 0x28 ; Slave offset + mov rcx, 0x02 ; Slave ICW3 values + call setup_pic + + ret +; Set up PIC +; input: +; rdi - command port +; rsi - data port +; rdx - offset +; rcx - ICW3 value +; Master: 0x11, 0x20, 0x04, 0x01 +; Slave: 0x11, 0x28, 0x02, 0x01 +setup_pic: + ; Step 0: rescue the offset FIRST, before dx gets reused for ports + mov r8b, dl ; r8b now safely holds the offset byte, forever + + ; Step 1: ICW1 -> command port + mov dx, di + mov al, 0x11 + out dx, al + + ; Step 2: ICW2 (offset) -> data port + mov dx, si + mov al, r8b + out dx, al + + ; Step 3: ICW3 -> data port (dx is UNCHANGED since step 2 — no reload needed) + mov al, cl + out dx, al + + ; Step 4: ICW4 -> data port (still no reload needed) + mov al, 0x01 + out dx, al + + ret + +; keyboard handler - Catch PIC interrupt +keyboard_handler: + push rax + push rdx + push rdi + push r8 + + mov dx, 0x60 + in al, dx + + ; convert ASCII + ; assuming output on r8 (as an example) + + ; Acording to x86_64 SystemV + mov rdi, r8 + call __keyboard_buffer_push + + mov al, 0x20 + out 0x20, al + + pop r8 + pop rdi + pop rdx + pop rax + iretq + ; Exception handler - shows what went wrong exception_handler: ; Save registers diff --git a/kernel.c b/kernel.c index e40176e..3b91275 100644 --- a/kernel.c +++ b/kernel.c @@ -20,16 +20,16 @@ typedef struct { void kmain(void) { user current_user = {.user_name = "admin", .user_hostname = "soraos", .user_id = 0}; - __clear_screen_colored(LIGHT_GREEN); + __clear_screen(); - printf("SoraOS Kernel Initialized!\n"); - printf("\tWelcome to SoraOS!\n"); - printf("\tKernel Version: %s\n", __KERNEL_VERSION); - printf("\tCompiled on: %s at %s\n\n", __DATE__, __TIME__); + printf("SoraOS Kernel Initialized\n"); + printf("\tWelcome to SoraOS\n"); + printf("\tKernel Version %s\n", __KERNEL_VERSION); + // printf("\tCompiled on: %s at %s\n\n", __DATE__, __TIME__); // TODO: CLI IDEA - int _count = printf("%s@%s:>", current_user.user_name, current_user.user_hostname); - scursor(_count, text_pos.line); + // int _count = printf("%s@%s:>", current_user.user_name, current_user.user_hostname); + // scursor(_count, text_pos.line); // TODO: Enable user input handling // char input_buffer[256]; diff --git a/stdio.h b/stdio.h index 9378208..943b8ea 100644 --- a/stdio.h +++ b/stdio.h @@ -11,15 +11,45 @@ #define VGA_MEMORY_ADDRESS 0xB8000 /* - * FOR INPUT - */ + * FOR INPUT + */ #define KEYBOARD_BUFFER_SIZE 256 +#define SCANCODE_LSHIFT 0x2A +#define SCANCODE_RSHIFT 0x36 +#define SCANCODE_CAPSLOCK 0x3A +#define RELEASE_MASK 0x80 + static char _keyboard_buffer[KEYBOARD_BUFFER_SIZE]; static uint16_t _kb_head = 0; static uint16_t _kb_tail = 0; +static char __g_shift_pressed = 0; +static char __g_caps_lock_active = 0; + +// C99 Designated Initializers for Unshifted ASCII Characters +static const char scancode_ascii_unshifted[128] = { + [0x01] = 27, // ESC + [0x02] = '1', [0x03] = '2', [0x04] = '3', [0x05] = '4', [0x06] = '5', [0x07] = '6', [0x08] = '7', [0x09] = '8', [0x0A] = '9', [0x0B] = '0', [0x0C] = '-', + [0x0D] = '=', [0x0E] = '\b', // Backspace + [0x0F] = '\t', // Tab + [0x10] = 'q', [0x11] = 'w', [0x12] = 'e', [0x13] = 'r', [0x14] = 't', [0x15] = 'y', [0x16] = 'u', [0x17] = 'i', [0x18] = 'o', [0x19] = 'p', [0x1A] = '[', + [0x1B] = ']', [0x1C] = '\n', // Enter + [0x1E] = 'a', [0x1F] = 's', [0x20] = 'd', [0x21] = 'f', [0x22] = 'g', [0x23] = 'h', [0x24] = 'j', [0x25] = 'k', [0x26] = 'l', [0x27] = ';', [0x28] = '\'', + [0x29] = '`', [0x2C] = 'z', [0x2D] = 'x', [0x2E] = 'c', [0x2F] = 'v', [0x30] = 'b', [0x31] = 'n', [0x32] = 'm', [0x33] = ',', [0x34] = '.', [0x35] = '/', + [0x39] = ' ' // Spacebar +}; + +// C99 Designated Initializers for Shifted ASCII Characters +static const char scancode_ascii_shifted[128] = { + [0x01] = 27, // ESC + [0x02] = '!', [0x03] = '@', [0x04] = '#', [0x05] = '$', [0x06] = '%', [0x07] = '^', [0x08] = '&', [0x09] = '*', [0x0A] = '(', [0x0B] = ')', + [0x0C] = '_', [0x0D] = '+', [0x0E] = '\b', [0x0F] = '\t', [0x10] = 'Q', [0x11] = 'W', [0x12] = 'E', [0x13] = 'R', [0x14] = 'T', [0x15] = 'Y', + [0x16] = 'U', [0x17] = 'I', [0x18] = 'O', [0x19] = 'P', [0x1A] = '{', [0x1B] = '}', [0x1C] = '\n', [0x1E] = 'A', [0x1F] = 'S', [0x20] = 'D', + [0x21] = 'F', [0x22] = 'G', [0x23] = 'H', [0x24] = 'J', [0x25] = 'K', [0x26] = 'L', [0x27] = ':', [0x28] = '"', [0x29] = '~', [0x2C] = 'Z', + [0x2D] = 'X', [0x2E] = 'C', [0x2F] = 'V', [0x30] = 'B', [0x31] = 'N', [0x32] = 'M', [0x33] = '<', [0x34] = '>', [0x35] = '?', [0x39] = ' '}; + /* IN VGA - Video Memory Arrya: * short * 1s byte (left most) -> TEXT COLOR @@ -29,8 +59,8 @@ static uint16_t _kb_tail = 0; typedef struct __attribute__((packed)) _VGA { unsigned char codepoint; // 3rd and 4th byte - unsigned char color; // 1st byte: text color, 2nd byte: background color - // LAST BIT IS BLINKING FLAG + unsigned char color; // 1st byte: text color, 2nd byte: background color + // LAST BIT IS BLINKING FLAG } _VGA; typedef enum _VGA_COLOR { @@ -70,8 +100,6 @@ static unsigned int tab_pos = 0; * END OF DECLARATIONS */ - - /* * START OF OUTPUT FUNCTIONS */ @@ -83,7 +111,7 @@ static inline unsigned char __vga_color_byte(_VGA_COLOR fg, _VGA_COLOR bg, int b unsigned char color = (bg << 4) | fg; if (blink) { color |= 0x80; // Set the blinking BIT - // to the highest bit + // to the highest bit } return color; } @@ -271,10 +299,10 @@ static int __printf_internal(const char *fmt, va_list args) { * TODO: Enable floating point support later * This requires enabling FPU in the kernel case 'f': { - double f = va_arg(args, double); - char buf[64]; - count += __print_string(ftoa(f, buf), DEFAULT_FG, DEFAULT_BG, 0); - break; + double f = va_arg(args, double); + char buf[64]; + count += __print_string(ftoa(f, buf), DEFAULT_FG, DEFAULT_BG, 0); + break; } */ @@ -306,157 +334,182 @@ int printf(const char *fmt, ...) { /* * END OF OUTPUT FUNCTIONS - */ - - - + */ /* * START OF INPUT FUNCTIONS */ static inline void outb(unsigned short port, unsigned char val) { - __asm__ volatile ("outb %0, %1" : : "a"(val), "Nd"(port)); + __asm__ volatile("outb %0, %1" : : "a"(val), "Nd"(port)); } static inline void __VGA_set_cursor_internal(unsigned int column, unsigned int line) { - if (column >= VGA_WIDTH) column = VGA_WIDTH - 1; - if (line >= VGA_HEIGHT) line = VGA_HEIGHT - 1; + if (column >= VGA_WIDTH) + column = VGA_WIDTH - 1; + if (line >= VGA_HEIGHT) + line = VGA_HEIGHT - 1; - unsigned short pos = line * VGA_WIDTH + column; + unsigned short pos = line * VGA_WIDTH + column; - // Send high byte - outb(0x3D4, 0x0E); - outb(0x3D5, (pos >> 8) & 0xFF); + // Send high byte + outb(0x3D4, 0x0E); + outb(0x3D5, (pos >> 8) & 0xFF); - // Send low byte - outb(0x3D4, 0x0F); - outb(0x3D5, pos & 0xFF); + // Send low byte + outb(0x3D4, 0x0F); + outb(0x3D5, pos & 0xFF); - cursor_pos.column = column; - cursor_pos.line = line; + cursor_pos.column = column; + cursor_pos.line = line; - text_pos.column = column; - text_pos.line = line; + text_pos.column = column; + text_pos.line = line; } static void __VGA_set_cursor_VGA_pos(_VGA_screen_space pos) { - __VGA_set_cursor_internal(pos.column, pos.line); + __VGA_set_cursor_internal(pos.column, pos.line); } static _VGA_screen_space get_cursor_pos() { - _VGA_screen_space __temp = {cursor_pos.column, cursor_pos.line}; - return __temp; + _VGA_screen_space __temp = {cursor_pos.column, cursor_pos.line}; + return __temp; } void scursor(unsigned int column, unsigned int line) { - __VGA_set_cursor_internal(column, line); + __VGA_set_cursor_internal(column, line); } static inline void __keyboard_buffer_push(char __c) { - _keyboard_buffer[_kb_head] = __c; - _kb_head = (_kb_head + 1) % KEYBOARD_BUFFER_SIZE; + _keyboard_buffer[_kb_head] = __c; + _kb_head = (_kb_head + 1) % KEYBOARD_BUFFER_SIZE; } static inline char __keyboard_buffer_pop() { - if (_kb_tail == _kb_head) { - return '\0'; + if (_kb_tail == _kb_head) { + return '\0'; + } + + char __c = _keyboard_buffer[_kb_tail]; + _kb_tail = (_kb_tail + 1) % KEYBOARD_BUFFER_SIZE; + return __c; +} + +static inline char __convert_ascii(uint8_t __scancode) { + char __code = __scancode & ~RELEASE_MASK; + if (__scancode & 0x80) { + // Key-released + if (__code == SCANCODE_LSHIFT || __code == SCANCODE_RSHIFT) { + __g_shift_pressed = 0; + } + return '\0'; + } + + if (__code == SCANCODE_LSHIFT || __code == SCANCODE_RSHIFT) { + __g_shift_pressed = 1; + return '\0'; + } + if (__code == SCANCODE_CAPSLOCK) { + __g_caps_lock_active = !__g_caps_lock_active; // Toggle Caps Lock + return '\0'; + } + + if ((unsigned char)__scancode >= 128) { + // Unknown scancodes or Out-of-Bounds + return '\0'; + } + + char __char = scancode_ascii_unshifted[__code]; + if (__char == '\0') { + return '\0'; // Key has no ASCII mapping (e.g., F1, Arrow keys) + } + + if (__char >= 'a' && __char <= 'z') { + char __make_uppercase = __g_shift_pressed ^ __g_caps_lock_active; + return __make_uppercase ? scancode_ascii_shifted[__code] : __char; + } else { + return __g_shift_pressed ? scancode_ascii_shifted[__code] : __char; + } + + return __char; +} + +void __keyboard_handle_scancode(uint8_t __scancode) { + char __temp = __convert_ascii(__scancode); + if (__temp == '\0') { + return; } - - char __c = _keyboard_buffer[_kb_tail]; - _kb_tail = (_kb_tail + 1) % KEYBOARD_BUFFER_SIZE; - return __c; -} - -static inline char __gets_internal(char *buffer, size_t max_length) { - size_t index = 0; - char __c; - - while (index < max_length - 1) { - __c = __keyboard_buffer_pop(); - if (__c == '\0') { - continue; - } - - if (__c == '\n' || __c == '\r') { - buffer[index] = '\0'; - break; - } - - buffer[index++] = __c; - } - - buffer[index] = '\0'; - return index; -} - -void gets(char *buffer, size_t max_length) { - __gets_internal(buffer, max_length); + __keyboard_buffer_push(__temp); } +/* static inline int __scanf_internal(const char *fmt, va_list args) { - char buffer[256]; - __gets_internal(buffer, sizeof(buffer)); + char buffer[256]; + __gets_internal(buffer, sizeof(buffer)); - const char* p = fmt; - char* in = buffer; + const char *p = fmt; + char *in = buffer; - int count = 0; + int count = 0; - while (*p) { - if (*p == '%') { - p++; + while (*p) { + if (*p == '%') { + p++; - if (*p == 'd') { - int* out = va_arg(args, int*); - int sign = 1; - int value = 0; + if (*p == 'd') { + int *out = va_arg(args, int *); + int sign = 1; + int value = 0; - if (*in == '-') { sign = -1; in++; } + if (*in == '-') { + sign = -1; + in++; + } - while (*in >= '0' && *in <= '9') { - value = value * 10 + (*in - '0'); - in++; - } + while (*in >= '0' && *in <= '9') { + value = value * 10 + (*in - '0'); + in++; + } - *out = value * sign; - count++; - } + *out = value * sign; + count++; + } - else if (*p == 's') { - char* out = va_arg(args, char*); - while (*in == ' ') in++; // skip spaces - while (*in && *in != ' ') { - *out++ = *in++; - } - *out = '\0'; - count++; - } + else if (*p == 's') { + char *out = va_arg(args, char *); + while (*in == ' ') + in++; // skip spaces + while (*in && *in != ' ') { + *out++ = *in++; + } + *out = '\0'; + count++; + } - else if (*p == 'c') { - char* out = va_arg(args, char*); - *out = *in++; - count++; - } - } + else if (*p == 'c') { + char *out = va_arg(args, char *); + *out = *in++; + count++; + } + } - p++; - } + p++; + } - va_end(args); + va_end(args); - return count; -} - -int scanf(const char *fmt, ...) { - va_list args; - va_start(args, fmt); - int result = __scanf_internal(fmt, args); - va_end(args); - return result; + return count; } +int scanf(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + int result = __scanf_internal(fmt, args); + va_end(args); + return result; +} +*/ #endif