From cc36c768cffb751d5919f2d699fabf94e6bf05da Mon Sep 17 00:00:00 2001 From: xamidev Date: Sun, 28 Dec 2025 10:28:17 +0100 Subject: [PATCH 1/3] Shitty broken keyboard driver BUT azerty-compatible --- Makefile | 2 +- src/idt/idt.S | 7 ++ src/idt/idt.c | 7 +- src/kbd/ps2.c | 230 +++++++++++++++++++++++++++++++++++++++++++++++ src/kbd/ps2.h | 25 ++++++ src/kmain.c | 3 + src/time/timer.c | 3 +- 7 files changed, 274 insertions(+), 3 deletions(-) create mode 100644 src/kbd/ps2.c create mode 100644 src/kbd/ps2.h diff --git a/Makefile b/Makefile index 641b1d7..6a90378 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ build: rm -f *.o - x86_64-elf-gcc -g -c -I src src/time/timer.c src/idt/idt.c src/mem/utils.c src/mem/gdt.c src/io/serial.c src/io/term.c src/io/printf.c src/kmain.c -Wall -Wextra -std=gnu99 -nostdlib -ffreestanding -fno-stack-protector -fno-stack-check -fno-PIC -ffunction-sections -fdata-sections -mcmodel=kernel + x86_64-elf-gcc -g -c -I src src/kbd/ps2.c src/time/timer.c src/idt/idt.c src/mem/utils.c src/mem/gdt.c src/io/serial.c src/io/term.c src/io/printf.c src/kmain.c -Wall -Wextra -std=gnu99 -nostdlib -ffreestanding -fno-stack-protector -fno-stack-check -fno-PIC -ffunction-sections -fdata-sections -mcmodel=kernel objcopy -O elf64-x86-64 -B i386 -I binary zap-light16.psf zap-light16.o nasm -f elf64 src/idt/idt.S -o idt_stub.o x86_64-elf-ld -o pepperk -T linker.ld *.o diff --git a/src/idt/idt.S b/src/idt/idt.S index 7cf344b..fe5cf58 100644 --- a/src/idt/idt.S +++ b/src/idt/idt.S @@ -300,4 +300,11 @@ align 16 vector_32_handler: push qword 0 push qword 32 + jmp interrupt_stub + +; PS/2 Keyboard +align 16 +vector_33_handler: + push qword 0 + push qword 33 jmp interrupt_stub \ No newline at end of file diff --git a/src/idt/idt.c b/src/idt/idt.c index 10df147..514e9ab 100644 --- a/src/idt/idt.c +++ b/src/idt/idt.c @@ -2,6 +2,7 @@ #include #include #include "../io/serial.h" +#include "../kbd/ps2.h" struct interrupt_descriptor idt[256]; struct idtr idt_reg; @@ -123,12 +124,16 @@ struct cpu_status_t* interrupt_dispatch(struct cpu_status_t* context) break; case 32: - serial_kputs("Tick!"); + //serial_kputs("Tick!"); ticks++; // Send an EOI so that we can continue having interrupts outb(0x20, 0x20); break; + case 33: + keyboard_handler(); + break; + default: serial_kputs("kernel: idt: Unexpected interrupt\n"); break; diff --git a/src/kbd/ps2.c b/src/kbd/ps2.c new file mode 100644 index 0000000..6565a71 --- /dev/null +++ b/src/kbd/ps2.c @@ -0,0 +1,230 @@ +// PS/2 Keyboard support + +#include "../io/serial.h" +#include "../io/printf.h" +#include "ps2.h" +#include + +// The key status bitfield will be used to see if ALT, CONTROL, or SHIFT is pressed +uint8_t key_status = 0b00000000; + +// Keymap pointers so we can change between different layouts +unsigned char* keymap; +unsigned char* keymap_shifted; + +unsigned char kbdus[128] = +{ + 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', /* 9 */ + '9', '0', '-', '=', '\b', /* Backspace */ + '\t', /* Tab */ + 'q', 'w', 'e', 'r', /* 19 */ + 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', /* Enter key */ + CTRL, /* 29 - Control */ + 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', /* 39 */ + '\'', '`', SHIFT, /* Left shift */ + '\\', 'z', 'x', 'c', 'v', 'b', 'n', /* 49 */ + 'm', ',', '.', '/', SHIFT, /* Right shift */ + '*', + ALT, /* 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 */ + '-', + 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 */ +}; + +unsigned char kbdus_shifted[128] = +{ + 0, 27, '!', '@', '#', '$', '%', '^', '&', '*', /* 9 */ + '(', ')', '_', '+', '\b', /* Backspace */ + '\t', /* Tab */ + 'Q', 'W', 'E', 'R', /* 19 */ + 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', /* Enter */ + CTRL, /* 29 */ + 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', /* 39 */ + '"', '~', SHIFT, /* Left shift */ + '|', 'Z', 'X', 'C', 'V', 'B', 'N', /* 49 */ + 'M', '<', '>', '?', SHIFT, /* Right shift */ + '*', + ALT, /* Alt */ + ' ', /* Space */ + 0, /* Caps lock */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, /* F10 */ + 0, /* Num lock */ + 0, /* Scroll lock */ + 0, 0, 0, + '-', + 0, 0, 0, + '+', + 0, 0, 0, + 0, 0, + 0, 0, 0, + 0, /* F11 */ + 0 /* F12 */ +}; + +// NOT THE REAL FR KEYMAP!! +// Some French keys have accents or weird symbols that aren't part of ASCII +// so they won't fit in 1 char. As a substitute for now, these will be +// changed to their ASCII counterparts (without accents, etc.) +unsigned char kbdfr[128] = +{ + 0, 27, '&', 'e', '"', '\'', '(', '-', 'e', '_', + 'c', 'a', ')', '=', '\b', + '\t', + 'a', 'z', 'e', 'r', + 't', 'y', 'u', 'i', 'o', 'p', '^', '$', '\n', + CTRL, + 'q', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', + 'u', '`', SHIFT, + '*', 'w', 'x', 'c', 'v', 'b', 'n', + ',', ';', ':', '!', SHIFT, + '*', + ALT, + ' ', + 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, + 0, + 0, + 0, 0, 0, + '-', + 0, 0, 0, + '+', + 0, 0, 0, + 0, 0, + 0, 0, 0, + 0, + 0 +}; + +unsigned char kbdfr_shifted[128] = +{ + 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', + '9', '0', '^', '+', '\b', + '\t', + 'A', 'Z', 'E', 'R', + 'T', 'Y', 'U', 'I', 'O', 'P', '^', 'L', '\n', + CTRL, + 'Q', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M', + '%', '~', SHIFT, + 'u', 'W', 'X', 'C', 'V', 'B', 'N', + '?', '.', '/', 'S', SHIFT, + '*', + ALT, + ' ', + 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, + 0, + 0, + 0, 0, 0, + '-', + 0, 0, 0, + '+', + 0, 0, 0, + 0, 0, + 0, 0, 0, + 0, + 0 +}; + +void keyboard_handler() +{ + unsigned char scancode = inb(0x60); + + // Key release (bit 7 set) + if (scancode & 0x80) + { + if (key_status & SHIFT_PRESSED) + { + serial_kputs("SHIFT was released!\n"); + key_status &= ~(1 << 0); // Unset SHIFT bit + } + + if (key_status & ALT_PRESSED) + { + serial_kputs("ALT was released!\n"); + key_status &= ~(1 << 1); // Unset ALT bit + } + + if (key_status & CTRL_PRESSED) + { + serial_kputs("CTRL was released!\n"); + key_status &= ~(1 << 2); // Unset CTRL bit + } + } + else + { + // Key press + unsigned char character; + + switch (keymap[scancode]) + { + case SHIFT: + serial_kputs("SHIFT "); + key_status |= (1 << 0); // SHIFT bit + break; + case ALT: + serial_kputs("ALT "); + key_status |= (1 << 1); + break; + case CTRL: + serial_kputs("CTRL "); + key_status |= (1 << 2); + break; + default: + character = (key_status & SHIFT_PRESSED) ? keymap_shifted[scancode] : keymap[scancode]; + printf("%c", character); + break; + } + + // Should we get a SHIFTED char or a regular one? + serial_kputs("key pressed!\n"); + } + + // End of Interrupt (to master PIC) + outb(0x20, 0x20); +} + +void keyboard_init(unsigned char layout) +{ + // Here we might go and select PS/2, USB, or other... (once we implement multiple keyboard protocols) + + // Keyboard layout selection + switch (layout) + { + case US: + keymap = kbdus; + keymap_shifted = kbdus_shifted; + break; + case FR: + keymap = kbdfr; + keymap_shifted = kbdfr_shifted; + break; + + default: + serial_kputs("Unsupported layout."); + break; + } +} \ No newline at end of file diff --git a/src/kbd/ps2.h b/src/kbd/ps2.h new file mode 100644 index 0000000..2ad8457 --- /dev/null +++ b/src/kbd/ps2.h @@ -0,0 +1,25 @@ +#ifndef PS2_H +#define PS2_H + +void keyboard_handler(); + +#define SHIFT_PRESSED 0b00000001 +#define ALT_PRESSED 0b00000010 +#define CTRL_PRESSED 0b00000100 + +enum SpecialKeys +{ + SHIFT = 255, + ALT = 254, + CTRL = 253 +}; + +enum KeyboardLayout +{ + US, + FR +}; + +void keyboard_init(unsigned char layout); + +#endif \ No newline at end of file diff --git a/src/kmain.c b/src/kmain.c index ffb1474..61c48fc 100644 --- a/src/kmain.c +++ b/src/kmain.c @@ -9,6 +9,7 @@ #include "idt/idt.h" #include "kernel.h" #include "time/timer.h" +#include "kbd/ps2.h" // Limine version used __attribute__((used, section(".limine_requests"))) @@ -57,6 +58,8 @@ void kmain() timer_init(); SET_INTERRUPTS; + keyboard_init(FR); + // Draw something printf("%s, %s!", "Hello", "world"); diff --git a/src/time/timer.c b/src/time/timer.c index 41415b4..1fe8565 100644 --- a/src/time/timer.c +++ b/src/time/timer.c @@ -42,7 +42,8 @@ void pic_enable() { // Enabling IRQ0 (unmasking it) but not the others uint8_t mask = inb(0x21); - mask &= ~(1 << 0); // Clear bit 0 (IRQ0) + mask &= ~(1 << 0); // Set IRQ0 (timer, clear bit 0) + mask &= ~(1 << 1); // Set IRQ1 (PS/2 Keyboard, clear bit 1) outb(0x21, mask); } From 4607b5aba5c7713b2bb3a6d8aaa0bfddd7dc40c1 Mon Sep 17 00:00:00 2001 From: xamidev Date: Sun, 28 Dec 2025 11:06:33 +0100 Subject: [PATCH 2/3] holy SHIFT --- src/io/term.c | 27 +++++++++++++++++++-- src/io/term.h | 1 + src/kbd/ps2.c | 66 ++++++++++++++++++++++++++++----------------------- src/kbd/ps2.h | 18 +++++++++++--- 4 files changed, 77 insertions(+), 35 deletions(-) diff --git a/src/io/term.c b/src/io/term.c index f2a913c..0852355 100644 --- a/src/io/term.c +++ b/src/io/term.c @@ -66,7 +66,19 @@ static void draw_char(char c, int px, int py, int fg, int bg) } } -static void putchar(char c) +static void erase_char(int px, int py) +{ + for (size_t y=0; y= framebuffer->width) { cursor.x = 0; @@ -87,7 +110,7 @@ static void putchar(char c) cursor.x++; } -// Overhead that could be avoided, right? +// Overhead that could be avoided, right? (for printf) void _putchar(char character) { putchar(character); diff --git a/src/io/term.h b/src/io/term.h index c7bcf5c..a240768 100644 --- a/src/io/term.h +++ b/src/io/term.h @@ -3,6 +3,7 @@ int term_init(); void kputs(const char* str); +void putchar(char c); enum TermColors { diff --git a/src/kbd/ps2.c b/src/kbd/ps2.c index 6565a71..3af8242 100644 --- a/src/kbd/ps2.c +++ b/src/kbd/ps2.c @@ -4,6 +4,7 @@ #include "../io/printf.h" #include "ps2.h" #include +#include "../io/term.h" // The key status bitfield will be used to see if ALT, CONTROL, or SHIFT is pressed uint8_t key_status = 0b00000000; @@ -156,50 +157,55 @@ void keyboard_handler() // Key release (bit 7 set) if (scancode & 0x80) { - if (key_status & SHIFT_PRESSED) + unsigned char code = scancode & 0x7F; + switch (code) { - serial_kputs("SHIFT was released!\n"); - key_status &= ~(1 << 0); // Unset SHIFT bit + // Clear the corresponding bit if corresponding key is released + case LEFT_SHIFT_PRESSED: + case RIGHT_SHIFT_PRESSED: + key_status &= ~SHIFT_PRESSED_BIT; + break; + case CTRL_PRESSED: + key_status &= ~CTRL_PRESSED_BIT; + break; + case ALT_PRESSED: + key_status &= ~ALT_PRESSED_BIT; + break; } - if (key_status & ALT_PRESSED) - { - serial_kputs("ALT was released!\n"); - key_status &= ~(1 << 1); // Unset ALT bit - } - - if (key_status & CTRL_PRESSED) - { - serial_kputs("CTRL was released!\n"); - key_status &= ~(1 << 2); // Unset CTRL bit - } + // Send EOI + outb(0x20, 0x20); + return; } else { // Key press - unsigned char character; - - switch (keymap[scancode]) + switch (scancode) { - case SHIFT: - serial_kputs("SHIFT "); - key_status |= (1 << 0); // SHIFT bit + // Set bits for corresponding special key press + case LEFT_SHIFT_PRESSED: + case RIGHT_SHIFT_PRESSED: + key_status |= SHIFT_PRESSED_BIT; break; - case ALT: - serial_kputs("ALT "); - key_status |= (1 << 1); + case CTRL_PRESSED: + key_status |= CTRL_PRESSED_BIT; break; - case CTRL: - serial_kputs("CTRL "); - key_status |= (1 << 2); + case ALT_PRESSED: + key_status |= ALT_PRESSED_BIT; break; + default: - character = (key_status & SHIFT_PRESSED) ? keymap_shifted[scancode] : keymap[scancode]; - printf("%c", character); - break; + { + // Should we get a SHIFTED char or a regular one? + unsigned char c = (key_status & SHIFT_PRESSED_BIT) ? keymap_shifted[scancode] : keymap[scancode]; + + if (c) + { + putchar(c); + } + } } - // Should we get a SHIFTED char or a regular one? serial_kputs("key pressed!\n"); } diff --git a/src/kbd/ps2.h b/src/kbd/ps2.h index 2ad8457..5b1c207 100644 --- a/src/kbd/ps2.h +++ b/src/kbd/ps2.h @@ -3,9 +3,9 @@ void keyboard_handler(); -#define SHIFT_PRESSED 0b00000001 -#define ALT_PRESSED 0b00000010 -#define CTRL_PRESSED 0b00000100 +#define SHIFT_PRESSED_BIT 0b00000001 +#define ALT_PRESSED_BIT 0b00000010 +#define CTRL_PRESSED_BIT 0b00000100 enum SpecialKeys { @@ -14,6 +14,18 @@ enum SpecialKeys CTRL = 253 }; +enum SpecialScancodes +{ + LEFT_SHIFT_PRESSED = 0x2A, + LEFT_SHIFT_RELEASED = 0xAA, + RIGHT_SHIFT_PRESSED = 0x36, + RIGHT_SHIFT_RELEASED = 0xB6, + CTRL_PRESSED = 0x1D, + CTRL_RELEASED = 0x9D, + ALT_PRESSED = 0x38, + ALT_RELEASED = 0xB8 +}; + enum KeyboardLayout { US, From b886f03f7adeb036c14664c7bae6d1fe6cc6a0eb Mon Sep 17 00:00:00 2001 From: xamidev Date: Sun, 28 Dec 2025 11:14:22 +0100 Subject: [PATCH 3/3] Quick backspace fix --- src/io/term.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/io/term.c b/src/io/term.c index 0852355..50d2552 100644 --- a/src/io/term.c +++ b/src/io/term.c @@ -87,11 +87,26 @@ void putchar(char c) return; } - // Improperly handled. + // TODO: Improperly handled. // When we're on an empty line it should get to the upper line's last character + // NOT just the last position possible; we would need to track the last line's character amount for that if (c == '\b') { - cursor.x--; + if (cursor.x == 0 && cursor.y == 0) + { + // Top-left corner + return; + } + + if (cursor.x == 0) + { + cursor.y--; + cursor.x = (framebuffer->width / FONT_WIDTH) -1; // here + } + else { + cursor.x--; + } + int px = cursor.x * FONT_WIDTH; int py = cursor.y * FONT_HEIGHT; erase_char(px, py);