From 4862eea9361f1c5755e93bcbe5b3dc5baa132b0e Mon Sep 17 00:00:00 2001 From: Tulio A M Mendes Date: Sat, 14 Feb 2026 02:24:24 -0300 Subject: [PATCH] fix: cmdline parsing, framebuffer fallback, UART serial input for TTY 1. cmdline: use separate tok_copy buffer for tokenization so token pointers are properly null-terminated; raw_copy stays pristine for /proc/cmdline. 2. framebuffer: remove Multiboot2 framebuffer request tag from boot.S so GRUB keeps EGA text mode (no pixel drawing routines yet). 3. serial input: enable UART RX interrupt (IER bit 0), route IRQ 4 (COM1) via IOAPIC to IDT vector 36, wire hal_uart_set_rx_callback to tty_input_char in tty_init(). /bin/sh now accepts serial input. 4. grub.cfg: add shell entry (init=/bin/sh), keep ring3 test with console=serial for smoke test performance. Tests: 20/20 smoke, cppcheck clean. --- include/hal/uart.h | 1 + iso/boot/grub/grub.cfg | 8 ++++++- src/arch/x86/arch_platform.c | 2 ++ src/arch/x86/boot.S | 11 ---------- src/hal/arm/uart.c | 4 ++++ src/hal/mips/uart.c | 4 ++++ src/hal/riscv/uart.c | 4 ++++ src/hal/x86/uart.c | 33 +++++++++++++++++++++++------ src/kernel/cmdline.c | 41 +++++++++++++++--------------------- src/kernel/tty.c | 2 ++ 10 files changed, 68 insertions(+), 42 deletions(-) diff --git a/include/hal/uart.h b/include/hal/uart.h index 6a5761f..bdb7173 100644 --- a/include/hal/uart.h +++ b/include/hal/uart.h @@ -4,5 +4,6 @@ void hal_uart_init(void); void hal_uart_putc(char c); int hal_uart_try_getc(void); +void hal_uart_set_rx_callback(void (*cb)(char)); #endif diff --git a/iso/boot/grub/grub.cfg b/iso/boot/grub/grub.cfg index fd6d943..7de57c2 100644 --- a/iso/boot/grub/grub.cfg +++ b/iso/boot/grub/grub.cfg @@ -12,7 +12,13 @@ menuentry "AdrOS (x86)" { } menuentry "AdrOS (x86) - ring3 test" { - multiboot2 /boot/adros-x86.bin ring3 + multiboot2 /boot/adros-x86.bin ring3 console=serial + module2 /boot/initrd.img + boot +} + +menuentry "AdrOS (x86) - shell" { + multiboot2 /boot/adros-x86.bin init=/bin/sh module2 /boot/initrd.img boot } diff --git a/src/arch/x86/arch_platform.c b/src/arch/x86/arch_platform.c index e73d9fa..2cd5430 100644 --- a/src/arch/x86/arch_platform.c +++ b/src/arch/x86/arch_platform.c @@ -129,11 +129,13 @@ int arch_platform_setup(const struct boot_info* bi) { /* Route ISA IRQs through IOAPIC: * IRQ 0 (PIT/Timer) -> IDT vector 32 * IRQ 1 (Keyboard) -> IDT vector 33 + * IRQ 4 (COM1 UART) -> IDT vector 36 * IRQ 11 (E1000 NIC) -> IDT vector 43 * IRQ 14 (ATA primary) -> IDT vector 46 * IRQ 15 (ATA secondary) -> IDT vector 47 */ ioapic_route_irq(0, 32, (uint8_t)bsp_id); ioapic_route_irq(1, 33, (uint8_t)bsp_id); + ioapic_route_irq(4, 36, (uint8_t)bsp_id); /* COM1 serial */ ioapic_route_irq_level(11, 43, (uint8_t)bsp_id); /* E1000 NIC (PCI: level-triggered, active-low) */ ioapic_route_irq(14, 46, (uint8_t)bsp_id); /* ATA primary */ ioapic_route_irq(15, 47, (uint8_t)bsp_id); /* ATA secondary */ diff --git a/src/arch/x86/boot.S b/src/arch/x86/boot.S index a3a064c..4427493 100644 --- a/src/arch/x86/boot.S +++ b/src/arch/x86/boot.S @@ -21,17 +21,6 @@ multiboot_header_start: .long multiboot_header_end - multiboot_header_start .long 0x100000000 - (MB_MAGIC + MB_ARCH + (multiboot_header_end - multiboot_header_start)) - /* Framebuffer request tag (type 5, optional) */ - .align 8 -fb_tag_start: - .word 5 /* type: framebuffer */ - .word 1 /* flags: optional (boot even if unavailable) */ - .long fb_tag_end - fb_tag_start - .long 1024 /* preferred width */ - .long 768 /* preferred height */ - .long 32 /* preferred depth (bpp) */ -fb_tag_end: - /* End tag */ .align 8 .word 0, 0 diff --git a/src/hal/arm/uart.c b/src/hal/arm/uart.c index 066cb62..cb86767 100644 --- a/src/hal/arm/uart.c +++ b/src/hal/arm/uart.c @@ -19,3 +19,7 @@ int hal_uart_try_getc(void) { } return -1; } + +void hal_uart_set_rx_callback(void (*cb)(char)) { + (void)cb; +} diff --git a/src/hal/mips/uart.c b/src/hal/mips/uart.c index c22c915..b170005 100644 --- a/src/hal/mips/uart.c +++ b/src/hal/mips/uart.c @@ -22,3 +22,7 @@ int hal_uart_try_getc(void) { } return -1; } + +void hal_uart_set_rx_callback(void (*cb)(char)) { + (void)cb; +} diff --git a/src/hal/riscv/uart.c b/src/hal/riscv/uart.c index 8d7eb9a..231bf1b 100644 --- a/src/hal/riscv/uart.c +++ b/src/hal/riscv/uart.c @@ -20,3 +20,7 @@ int hal_uart_try_getc(void) { } return -1; } + +void hal_uart_set_rx_callback(void (*cb)(char)) { + (void)cb; +} diff --git a/src/hal/x86/uart.c b/src/hal/x86/uart.c index 37dc176..1c5b55e 100644 --- a/src/hal/x86/uart.c +++ b/src/hal/x86/uart.c @@ -1,18 +1,39 @@ #include "hal/uart.h" #include "io.h" +#include "arch/x86/idt.h" #include #define UART_BASE 0x3F8 +static void (*uart_rx_cb)(char) = 0; + +static void uart_irq_handler(struct registers* regs) { + (void)regs; + while (inb(UART_BASE + 5) & 0x01) { + char c = (char)inb(UART_BASE); + if (uart_rx_cb) uart_rx_cb(c); + } +} + void hal_uart_init(void) { + outb(UART_BASE + 1, 0x00); /* Disable all interrupts */ + outb(UART_BASE + 3, 0x80); /* Enable DLAB */ + outb(UART_BASE + 0, 0x03); /* Baud 38400 */ outb(UART_BASE + 1, 0x00); - outb(UART_BASE + 3, 0x80); - outb(UART_BASE + 0, 0x03); - outb(UART_BASE + 1, 0x00); - outb(UART_BASE + 3, 0x03); - outb(UART_BASE + 2, 0xC7); - outb(UART_BASE + 4, 0x0B); + outb(UART_BASE + 3, 0x03); /* 8N1 */ + outb(UART_BASE + 2, 0xC7); /* Enable FIFO */ + outb(UART_BASE + 4, 0x0B); /* DTR + RTS + OUT2 */ + + /* Register IRQ 4 handler (IDT vector 36 = 32 + 4) */ + register_interrupt_handler(36, uart_irq_handler); + + /* Enable receive data available interrupt (IER bit 0) */ + outb(UART_BASE + 1, 0x01); +} + +void hal_uart_set_rx_callback(void (*cb)(char)) { + uart_rx_cb = cb; } void hal_uart_putc(char c) { diff --git a/src/kernel/cmdline.c b/src/kernel/cmdline.c index a1029e1..0677b04 100644 --- a/src/kernel/cmdline.c +++ b/src/kernel/cmdline.c @@ -6,14 +6,15 @@ /* ---- Static storage ---- */ -static char raw_copy[CMDLINE_MAX]; +static char raw_copy[CMDLINE_MAX]; /* pristine copy for /proc/cmdline */ +static char tok_copy[CMDLINE_MAX]; /* tokenized copy — pointers live here */ /* Kernel-recognized "key=value" parameters */ #define KPARAM_MAX 16 struct kparam { const char* key; - const char* value; /* points into raw_copy */ + const char* value; /* points into tok_copy */ }; static struct kparam kparams[KPARAM_MAX]; @@ -88,17 +89,15 @@ void cmdline_parse(const char* raw) { strncpy(raw_copy, raw, CMDLINE_MAX - 1); raw_copy[CMDLINE_MAX - 1] = '\0'; - /* We'll tokenize a second working copy in-place. - * We can reuse raw_copy since we split by replacing ' ' with '\0'. */ - char work[CMDLINE_MAX]; - strncpy(work, raw_copy, CMDLINE_MAX - 1); - work[CMDLINE_MAX - 1] = '\0'; + /* Tokenize a second copy in-place — all pointers will live here */ + strncpy(tok_copy, raw, CMDLINE_MAX - 1); + tok_copy[CMDLINE_MAX - 1] = '\0'; char* tokens[128]; int ntokens = 0; /* Tokenize by whitespace */ - char* p = work; + char* p = tok_copy; while (*p && ntokens < 128) { while (*p == ' ' || *p == '\t') p++; if (!*p) break; @@ -145,34 +144,30 @@ void cmdline_parse(const char* raw) { /* "key=value" form */ size_t keylen = (size_t)(eq - tok); if (is_known_kv_key(tok, keylen)) { - /* Kernel param: store in raw_copy so pointers remain valid */ - size_t off = (size_t)(tok - work); if (kparam_count < KPARAM_MAX) { - /* Point key/value into raw_copy */ - raw_copy[off + keylen] = '\0'; /* split at '=' */ - kparams[kparam_count].key = &raw_copy[off]; - kparams[kparam_count].value = &raw_copy[off + keylen + 1]; + /* Split "key=value" in tok_copy at '=' */ + char* eq_ptr = (char*)(uintptr_t)eq; + *eq_ptr = '\0'; + kparams[kparam_count].key = tok; + kparams[kparam_count].value = eq_ptr + 1; kparam_count++; } } else { /* Unrecognized key=value → init envp */ if (init_envc < CMDLINE_MAX_ENVS) { - size_t off = (size_t)(tok - work); - init_envp[init_envc++] = &raw_copy[off]; + init_envp[init_envc++] = tok; } } } else { /* Plain token (no '=') */ if (is_known_flag(tok)) { if (kflag_count < KFLAG_MAX) { - size_t off = (size_t)(tok - work); - kflags[kflag_count++] = &raw_copy[off]; + kflags[kflag_count++] = tok; } } else if (!has_char(tok, '.')) { /* No '.' and not recognized → init argv */ if (init_argc < CMDLINE_MAX_ARGS) { - size_t off = (size_t)(tok - work); - init_argv[init_argc++] = &raw_copy[off]; + init_argv[init_argc++] = tok; } } /* Tokens with '.' but no '=' (like module params) are @@ -182,13 +177,11 @@ void cmdline_parse(const char* raw) { /* After "--": everything goes to init */ if (eq) { if (init_envc < CMDLINE_MAX_ENVS) { - size_t off = (size_t)(tok - work); - init_envp[init_envc++] = &raw_copy[off]; + init_envp[init_envc++] = tok; } } else { if (init_argc < CMDLINE_MAX_ARGS) { - size_t off = (size_t)(tok - work); - init_argv[init_argc++] = &raw_copy[off]; + init_argv[init_argc++] = tok; } } } diff --git a/src/kernel/tty.c b/src/kernel/tty.c index 1118a9d..16b6c26 100644 --- a/src/kernel/tty.c +++ b/src/kernel/tty.c @@ -10,6 +10,7 @@ #include "errno.h" #include "hal/cpu.h" +#include "hal/uart.h" #include "utils.h" #define TTY_LINE_MAX 256 @@ -460,6 +461,7 @@ void tty_init(void) { tty_fg_pgrp = 0; keyboard_set_callback(tty_keyboard_cb); + hal_uart_set_rx_callback(tty_input_char); static const struct file_operations tty_fops = { .read = tty_devfs_read, -- 2.43.0