From 498e013fcf62151b3226e3803fb27a45ef2221cf Mon Sep 17 00:00:00 2001 From: Atheria Date: Tue, 8 Jul 2025 16:23:48 +0700 Subject: [PATCH] Keyboard + 4KHz PIC --- Boot/boot.asm | 7 ++++ Kernel/Core/Kernel.c | 30 +++++++++------ Kernel/Core/Kernel.h | 3 ++ Kernel/Drivers/Driver.c | 32 ++++++++++++++++ Kernel/Drivers/Driver.h | 30 +++++++++++++++ Kernel/Drivers/Interrupts.c | 20 +++++++--- Kernel/Drivers/Keyboard.c | 73 +++++++++++++++++++++++++++++++++++++ grub.cfg | 1 + meson.build | 4 +- 9 files changed, 183 insertions(+), 17 deletions(-) create mode 100644 Kernel/Drivers/Driver.c create mode 100644 Kernel/Drivers/Driver.h create mode 100644 Kernel/Drivers/Keyboard.c diff --git a/Boot/boot.asm b/Boot/boot.asm index 8fb3d49..8715fff 100644 --- a/Boot/boot.asm +++ b/Boot/boot.asm @@ -157,6 +157,13 @@ long_mode: ; Clear direction flag cld + + ; DEBUG: Write 'BOOT' to VGA before calling C code + mov rax, 0xb8000 + mov word [rax], 0x0442 ; Red 'B' + mov word [rax+2], 0x044F ; Red 'O' + mov word [rax+4], 0x044F ; Red 'O' + mov word [rax+6], 0x0454 ; Red 'T' ; Pass multiboot info to kernel mov rdi, [multiboot_magic] diff --git a/Kernel/Core/Kernel.c b/Kernel/Core/Kernel.c index a3763f3..ae8aa65 100644 --- a/Kernel/Core/Kernel.c +++ b/Kernel/Core/Kernel.c @@ -10,7 +10,11 @@ #include "../System/Gdt.h" #include "../Process/UserMode.h" #include "../Drivers/Io.h" +#include "../Drivers/Driver.h" #include "Panic.h" + +// Driver registration +extern void KeyboardRegister(void); int CurrentLine = 0; int CurrentColumn = 0; void ClearScreen(){ @@ -124,7 +128,7 @@ void PrintKernelAt(const char *str, int line, int col) { } // Fast print - no bounds checking, direct memory write -static inline void FastPrint(const char *str, int line, int col) { +void FastPrint(const char *str, int line, int col) { uint16_t *vidptr = (uint16_t*)0xb8000; int pos = line * 80 + col; @@ -134,13 +138,13 @@ static inline void FastPrint(const char *str, int line, int col) { } // Fast print single character -static inline void FastPrintChar(char c, int line, int col) { +void FastPrintChar(char c, int line, int col) { uint16_t *vidptr = (uint16_t*)0xb8000; vidptr[line * 80 + col] = (0x03 << 8) | c; } // Fast print hex number -static inline void FastPrintHex(uint64_t num, int line, int col) { +void FastPrintHex(uint64_t num, int line, int col) { uint16_t *vidptr = (uint16_t*)0xb8000; int pos = line * 80 + col; @@ -169,14 +173,14 @@ static inline void FastPrintHex(uint64_t num, int line, int col) { void task1(void) { while (1) { FastPrint("T1 running", 10, 0); - for(volatile int i = 0; i < 10000; i++); // Faster loop + for(volatile int i = 0; i < 100; i++); // Tiny loop } } void task2(void) { while (1) { FastPrint("T2 running", 11, 0); - for(volatile int i = 0; i < 10000; i++); // Faster loop + for(volatile int i = 0; i < 100; i++); // Tiny loop } } void UserTask(void) { @@ -201,10 +205,11 @@ void UserTask(void) { void task3(void) { while (1) { FastPrint("T3 kernel", 12, 0); - for(volatile int i = 0; i < 10000; i++); // Faster loop + for(volatile int i = 0; i < 100; i++); // Tiny loop } } void KernelMain(uint32_t magic, uint32_t info) { + ClearScreen(); PrintKernel("VoidFrame Kernel - Version 0.0.1-alpha\n"); PrintKernel("Initializing GDT...\n"); @@ -219,18 +224,21 @@ void KernelMain(uint32_t magic, uint32_t info) { MemoryInit(); PrintKernel("Initializing Processes...\n"); ProcessInit(); + PrintKernel("Initializing Drivers...\n"); + KeyboardRegister(); + DriverInit(); PrintKernel("Process system ready\n"); CreateProcess(task1); CreateProcess(task2); CreateProcess(task3); CreateUserProcess(UserTask); // Ring 3 process - // Setup faster timer (PIT) - ~1000Hz instead of default 18.2Hz + // BLAZING FAST timer - ~4000Hz for maximum concurrency outb(0x43, 0x36); // Command: channel 0, lobyte/hibyte, rate generator - outb(0x40, 0xA9); // Low byte of divisor (1193 = ~1000Hz) - outb(0x40, 0x04); // High byte of divisor + outb(0x40, 0x4B); // Low byte of divisor (299 = ~4000Hz) + outb(0x40, 0x01); // High byte of divisor - // Enable timer interrupt (IRQ0) - outb(0x21, inb(0x21) & ~0x01); + // Enable timer (IRQ0) and keyboard (IRQ1) interrupts + outb(0x21, inb(0x21) & ~0x03); // Enable IRQ0 and IRQ1 // Enable all interrupts asm volatile("sti"); diff --git a/Kernel/Core/Kernel.h b/Kernel/Core/Kernel.h index 804f9ce..8968405 100644 --- a/Kernel/Core/Kernel.h +++ b/Kernel/Core/Kernel.h @@ -7,4 +7,7 @@ void PrintKernel(const char *str); void PrintKernelInt(int num); void PrintKernelHex(uint64_t hex); void PrintKernelAt(const char *str, int line, int col); +void FastPrint(const char *str, int line, int col); +void FastPrintHex(uint64_t num, int line, int col); +void FastPrintChar(char c, int line, int col); #endif diff --git a/Kernel/Drivers/Driver.c b/Kernel/Drivers/Driver.c new file mode 100644 index 0000000..4fdb780 --- /dev/null +++ b/Kernel/Drivers/Driver.c @@ -0,0 +1,32 @@ +#include "Driver.h" +#include "../Core/Panic.h" + +#define MAX_DRIVERS 16 + +static Driver* drivers[MAX_DRIVERS]; +static int driver_count = 0; + +void DriverRegister(Driver* driver) { + if (!driver || driver_count >= MAX_DRIVERS) { + Panic("Driver registration failed"); + } + + drivers[driver_count++] = driver; +} + +void DriverInit(void) { + for (int i = 0; i < driver_count; i++) { + if (drivers[i]->init) { + drivers[i]->init(); + } + } +} + +Driver* DriverGet(DriverType type) { + for (int i = 0; i < driver_count; i++) { + if (drivers[i]->type == type) { + return drivers[i]; + } + } + return 0; +} \ No newline at end of file diff --git a/Kernel/Drivers/Driver.h b/Kernel/Drivers/Driver.h new file mode 100644 index 0000000..38722c4 --- /dev/null +++ b/Kernel/Drivers/Driver.h @@ -0,0 +1,30 @@ +#ifndef DRIVER_H +#define DRIVER_H + +#include "../Core/stdint.h" + +// Driver types +typedef enum { + DRIVER_KEYBOARD, + DRIVER_MOUSE, + DRIVER_NETWORK, + DRIVER_STORAGE, + DRIVER_MAX +} DriverType; + +// Driver interface - all drivers implement this +typedef struct { + DriverType type; + const char* name; + void (*init)(void); + void (*handle_interrupt)(uint8_t irq); + int (*read)(void* buffer, uint32_t size); + int (*write)(const void* buffer, uint32_t size); +} Driver; + +// Driver registry +void DriverRegister(Driver* driver); +void DriverInit(void); +Driver* DriverGet(DriverType type); + +#endif \ No newline at end of file diff --git a/Kernel/Drivers/Interrupts.c b/Kernel/Drivers/Interrupts.c index ee7e285..97cb7d4 100644 --- a/Kernel/Drivers/Interrupts.c +++ b/Kernel/Drivers/Interrupts.c @@ -2,7 +2,7 @@ #include "../Core/Kernel.h" #include "Io.h" #include "../Process/Process.h" -#include "../Core/stdint.h" +#include "Driver.h" #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) @@ -32,7 +32,7 @@ void itoa(uint64_t num, char* str) { } // Fast tick display using direct memory write -static inline void FastDisplayTicks(uint64_t ticks) { +static void FastDisplayTicks(uint64_t ticks) { uint16_t *vidptr = (uint16_t*)0xb8000; int pos = 20 * 80; // Line 20 @@ -67,19 +67,29 @@ static inline void FastDisplayTicks(uint64_t ticks) { // The C-level interrupt handler void InterruptHandler(struct Registers* regs) { + // Handle keyboard interrupt (IRQ1, remapped to 33) + if (regs->interrupt_number == 33) { + Driver* kbd = DriverGet(DRIVER_KEYBOARD); + if (kbd && kbd->handle_interrupt) { + kbd->handle_interrupt(1); + } + outb(0x20, 0x20); // EOI + return; + } + // Handle timer interrupt (IRQ0, remapped to 32) if (likely(regs->interrupt_number == 32)) { tick_count++; - // Fast tick display every 100 ticks to reduce overhead - if ((tick_count & 0x3F) == 0) { // Every 64 ticks + // Display ticks rarely to reduce overhead + if ((tick_count & 0x3FF) == 0) { // Every 1024 ticks FastDisplayTicks(tick_count); } // Send EOI to master PIC outb(0x20, 0x20); - // Do preemptive scheduling directly + // BLAZING FAST - schedule on EVERY interrupt ScheduleFromInterrupt(regs); return; } diff --git a/Kernel/Drivers/Keyboard.c b/Kernel/Drivers/Keyboard.c new file mode 100644 index 0000000..cda468a --- /dev/null +++ b/Kernel/Drivers/Keyboard.c @@ -0,0 +1,73 @@ +#include "Driver.h" +#include "Io.h" +#include "../Core/Kernel.h" + +#define KEYBOARD_DATA_PORT 0x60 +#define KEYBOARD_STATUS_PORT 0x64 + +// Simple US keyboard layout +static char keymap[128] = { + 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', + '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', + 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', + 0, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, + '*', 0, ' ' +}; + +static char key_buffer[256]; +static int buffer_head = 0; +static int buffer_tail = 0; + +static void KeyboardInit(void) { + // Keyboard is already initialized by BIOS + FastPrint("Keyboard ready", 15, 0); +} + +static void KeyboardInterrupt(uint8_t irq) { + if (irq != 1) return; // IRQ1 = keyboard + + uint8_t scancode = inb(KEYBOARD_DATA_PORT); + + // Only handle key press (not release) + if (scancode & 0x80) return; + + char key = keymap[scancode]; + if (key) { + // Add to buffer + int next_head = (buffer_head + 1) % 256; + if (next_head != buffer_tail) { + key_buffer[buffer_head] = key; + buffer_head = next_head; + + // Echo key to screen + FastPrintChar(key, 16, (buffer_head % 80)); + } + } +} + +static int KeyboardRead(void* buffer, uint32_t size) { + char* buf = (char*)buffer; + int count = 0; + + while (buffer_tail != buffer_head && count < size) { + buf[count++] = key_buffer[buffer_tail]; + buffer_tail = (buffer_tail + 1) % 256; + } + + return count; +} + +// Keyboard driver instance +static Driver keyboard_driver = { + .type = DRIVER_KEYBOARD, + .name = "PS2 Keyboard", + .init = KeyboardInit, + .handle_interrupt = KeyboardInterrupt, + .read = KeyboardRead, + .write = 0 // Keyboard is input only +}; + +// Auto-register function +void KeyboardRegister(void) { + DriverRegister(&keyboard_driver); +} \ No newline at end of file diff --git a/grub.cfg b/grub.cfg index e443112..b017221 100644 --- a/grub.cfg +++ b/grub.cfg @@ -2,6 +2,7 @@ set timeout=0 set default=0 menuentry "VoidFrame" { + set gfxpayload=text multiboot2 /boot/voidframe.krnl boot } diff --git a/meson.build b/meson.build index 506f988..664ae31 100644 --- a/meson.build +++ b/meson.build @@ -62,7 +62,9 @@ c_sources = [ 'Kernel/System/Syscall.c', 'Kernel/Drivers/Interrupts.c', 'Kernel/Drivers/Pic.c', - 'Kernel/Drivers/Cpu.c' + 'Kernel/Drivers/Cpu.c', + 'Kernel/Drivers/Driver.c', + 'Kernel/Drivers/Keyboard.c' ] # Build include flags