From ba16f38c79ed986110420195133cbdf671a0a889 Mon Sep 17 00:00:00 2001 From: AfonsoCMSousa Date: Wed, 5 Aug 2026 02:23:54 +0100 Subject: [PATCH] Feat: Keyboard strokes working and in buffer --- boot/elevator.asm | 39 ++++++--------------------- boot/kernel.asm | 65 ++++++++++++++++++++++++++++++++++++++++++++ build.sh | 23 +++++++++------- kernel.c | 17 +++++++----- linker.ld | 4 +++ stdio.h | 69 ++++++++++++++++++++++++++++++++++++++++------- 6 files changed, 161 insertions(+), 56 deletions(-) diff --git a/boot/elevator.asm b/boot/elevator.asm index ded6c48..6da1326 100644 --- a/boot/elevator.asm +++ b/boot/elevator.asm @@ -1,6 +1,10 @@ ; File: elevator.asm ; Stage 2 Bootloader - No size limit! ; Job: Load kernel, set up GDT, switch to 64-bit mode, jump to kernel +%ifndef KERNEL_SECTORS +%define KERNEL_SECTORS 10 ; fallback default if build.sh doesn't override it +%endif + [org 0x7e00] [bits 16] @@ -104,7 +108,7 @@ load_kernel: ; Set up DAP (Disk Address Packet) mov word [dap_size], 0x10 - mov word [dap_sectors], 10 + mov word [dap_sectors], KERNEL_SECTORS mov word [dap_offset], 0x0000 mov word [dap_segment], 0x1000 mov dword [dap_lba_low], 6 ; LBA 6 = bytes 3072+ (sector 7 in CHS) @@ -136,7 +140,7 @@ load_kernel: ; Read using CHS mov ah, 0x02 ; Read function - mov al, 10 ; Number of sectors + mov al, KERNEL_SECTORS ; Number of sectors mov ch, 0 ; Cylinder 0 mov cl, 7 ; Sector 7 mov dh, 0 ; Head 0 @@ -490,7 +494,6 @@ 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 @@ -518,8 +521,6 @@ long_mode: mov rsi, before_kernel_msg call print_64 - sti ; Enable interrupts before jumping to kernel - ; JUMP TO KERNEL! call KERNEL_OFFSET @@ -624,32 +625,6 @@ setup_pic: 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 @@ -707,6 +682,8 @@ exception_handler: ; Dummy interrupt handler for IRQs (not CPU exceptions) dummy_handler: + mov al, 0x20 + out 0x20, al ; Send EOI to PIC iretq idt_descriptor: diff --git a/boot/kernel.asm b/boot/kernel.asm index 8fffe69..84f3197 100644 --- a/boot/kernel.asm +++ b/boot/kernel.asm @@ -2,14 +2,79 @@ ; Assembly entry point for the kernel [bits 64] [extern kmain] ; kmain is defined in kernel.c +[extern __keyboard_handle_scancode] +[extern __bss_start] +[extern __bss_end] global _start ; Make _start visible to linker _start: + call fill_idt + +; IMPORTANT + ; Zero out the .bss section + cld + mov rdi, __bss_start + mov rcx, __bss_end + sub rcx, rdi + xor rax, rax + rep stosb + ; We're already in 64-bit mode with stack set up ; Just call the C kernel + sti call kmain ; If kmain returns, hang jmp $ + hlt + +; Set up a minimal IDT +fill_idt: + ; Fill IDT with different handlers for different exceptions + mov rdi, 0x4210 ; IDT location + mov rax, keyboard_handler + + mov word [rdi], ax ; Offset low + mov word [rdi + 2], 0x18 ; Code segment + mov byte [rdi + 4], 0 ; IST + mov byte [rdi + 5], 0x8E ; Present, interrupt gate + shr rax, 16 + mov word [rdi + 6], ax ; Offset middle + shr rax, 16 + mov dword [rdi + 8], eax ; Offset high + mov dword [rdi + 12], 0 ; Reserved + ret + +; keyboard handler - Catch PIC interrupt +keyboard_handler: + push rax + push rdx + push rdi + push rcx + push rsi + push r8 + push r9 + push r10 + push r11 + + mov dx, 0x60 + in al, dx + + mov dil, al + call __keyboard_handle_scancode + + mov al, 0x20 + out 0x20, al + + pop r11 + pop r10 + pop r9 + pop r8 + pop rsi + pop rcx + pop rdi + pop rdx + pop rax + iretq diff --git a/build.sh b/build.sh index b3e8e59..fe7f9fc 100755 --- a/build.sh +++ b/build.sh @@ -24,22 +24,27 @@ echo -e "${GREEN}✓${NC} Folders created.${NC}" echo -e "${BLUE}[1/6]${NC} Assembling Stage 1 bootloader (MBR)..." nasm -f bin ./boot/boot.asm -o ./bin/boot.bin -# Step 2: Assemble Stage 2 bootloader (extended loader) -echo -e "${BLUE}[2/6]${NC} Assembling Stage 2 bootloader..." -nasm -f bin ./boot/elevator.asm -o ./bin/elevator.bin +# Step 2: Compile kernel C code +echo -e "${BLUE}[2/6]${NC} Compiling kernel..." +gcc -ffreestanding -c kernel.c -o ./obj/kernel.c.o -mcmodel=large -mno-red-zone -fno-pic -fno-pie -static -fno-stack-protector -nostdlib -mno-mmx -mno-sse -mno-sse2 -m64 # Step 3: Assemble kernel entry point echo -e "${BLUE}[3/6]${NC} Assembling kernel entry..." nasm -f elf64 ./boot/kernel.asm -o ./obj/kernel.asm.o -# Step 4: Compile kernel C code -echo -e "${BLUE}[4/6]${NC} Compiling kernel..." -gcc -ffreestanding -c kernel.c -o ./obj/kernel.c.o -mcmodel=large -mno-red-zone -fno-pic -fno-pie -static -fno-stack-protector -nostdlib -mno-mmx -mno-sse -mno-sse2 -m64 - -# Step 5: Link kernel -echo -e "${BLUE}[5/6]${NC} Linking kernel..." +# Step 4: Link kernel +echo -e "${BLUE}[4/6]${NC} Linking kernel..." ld -T linker.ld -o ./bin/kernel.bin ./obj/kernel.asm.o ./obj/kernel.c.o --oformat binary --nostdlib +# Step 4.5: Calculate kernel size in sectors +KERNEL_SIZE=$(stat -f%z ./bin/kernel.bin 2>/dev/null || stat -c%s ./bin/kernel.bin 2>/dev/null) +SECTORS=$(( (KERNEL_SIZE + 511) / 512 )) #Round up to nearest sector +echo -e "${YELLOW}Kernel size: ${KERNEL_SIZE} bytes, which is ${SECTORS} sectors.${NC}" + +# Step 5: Assemble Stage 2 bootloader (extended loader) +echo -e "${BLUE}[5/6]${NC} Assembling Stage 2 bootloader..." +nasm -f bin ./boot/elevator.asm -D KERNEL_SECTORS=$SECTORS -o ./bin/elevator.bin + # Step 6: Create OS image echo -e "${BLUE}[6/6]${NC} Creating OS image..." cat ./bin/boot.bin ./bin/elevator.bin ./bin/kernel.bin > os.bin diff --git a/kernel.c b/kernel.c index 3b91275..705e6e8 100644 --- a/kernel.c +++ b/kernel.c @@ -25,16 +25,21 @@ void kmain(void) { 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("\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]; - // scanf("%s", input_buffer); - // printf("\nYou entered: %s\n", input_buffer); + char input_buffer[256] = {0}; + gets(input_buffer, sizeof(input_buffer)); + + printf("Input buffer contents in hex:\n"); + for (int i = 0; input_buffer[i] != '\0'; i++) { + printf("[%x]", (unsigned char)input_buffer[i]); + } + printf("\nYou entered: %s\n", input_buffer); // Infinite loop while (1) { diff --git a/linker.ld b/linker.ld index e477fcb..e403f1b 100644 --- a/linker.ld +++ b/linker.ld @@ -20,7 +20,11 @@ SECTIONS } .bss : { + __bss_start = .; + *(.bss) *(COMMON) + + __bss_end = .; } } diff --git a/stdio.h b/stdio.h index 943b8ea..76010e8 100644 --- a/stdio.h +++ b/stdio.h @@ -4,6 +4,7 @@ #include "types.h" #include #include +#include #define VGA_WIDTH 80 #define VGA_HEIGHT 25 @@ -21,9 +22,9 @@ #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 volatile unsigned char _keyboard_buffer[KEYBOARD_BUFFER_SIZE]; +static volatile uint16_t _kb_head = 0; +static volatile uint16_t _kb_tail = 0; static char __g_shift_pressed = 0; static char __g_caps_lock_active = 0; @@ -396,7 +397,7 @@ static inline char __keyboard_buffer_pop() { } static inline char __convert_ascii(uint8_t __scancode) { - char __code = __scancode & ~RELEASE_MASK; + unsigned char __code = __scancode & ~RELEASE_MASK; if (__scancode & 0x80) { // Key-released if (__code == SCANCODE_LSHIFT || __code == SCANCODE_RSHIFT) { @@ -434,12 +435,61 @@ static inline char __convert_ascii(uint8_t __scancode) { return __char; } +uint8_t __scancode_h[128] = {0}; +static uint32_t __total_isr_calls = 0; + void __keyboard_handle_scancode(uint8_t __scancode) { - char __temp = __convert_ascii(__scancode); - if (__temp == '\0') { - return; - } - __keyboard_buffer_push(__temp); + __total_isr_calls++; + + char __temp = __convert_ascii(__scancode); + static uint8_t __index = 0; + + if (__index < sizeof(__scancode_h)) { + __scancode_h[__index++] = __scancode; + } + + if (__temp == '\0') { + return; + } + __keyboard_buffer_push(__temp); +} + +void __dump_scancode_history() { + printf("Scancode History: \n"); + printf("Total ISR Calls: %u\n", __total_isr_calls); + for (size_t i = 0; i < sizeof(__scancode_h); i++) { + if (__scancode_h[i] != 0) { + printf("[%x] = %c\n", __scancode_h[i], __convert_ascii(__scancode_h[i])); + } + } + printf("\n"); +} + +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); } /* @@ -509,7 +559,6 @@ int scanf(const char *fmt, ...) { va_end(args); return result; } - */ #endif