]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
fix: cmdline parsing, framebuffer fallback, UART serial input for TTY
authorTulio A M Mendes <[email protected]>
Sat, 14 Feb 2026 05:24:24 +0000 (02:24 -0300)
committerTulio A M Mendes <[email protected]>
Sat, 14 Feb 2026 05:24:24 +0000 (02:24 -0300)
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
iso/boot/grub/grub.cfg
src/arch/x86/arch_platform.c
src/arch/x86/boot.S
src/hal/arm/uart.c
src/hal/mips/uart.c
src/hal/riscv/uart.c
src/hal/x86/uart.c
src/kernel/cmdline.c
src/kernel/tty.c

index 6a5761f439056690091bf32c1b0f6090ffc096f1..bdb71732202bf7675288d31c249e0d478b826ef3 100644 (file)
@@ -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
index fd6d94399350b91dff31d59fd4c4a45b2a21240e..7de57c2902a86ee412c2bd2b3237711b7173a482 100644 (file)
@@ -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
 }
index e73d9fa811c901fb4c48c4f10484f0e4f92d5006..2cd54304067760ef13bdcb65547f14a3502678da 100644 (file)
@@ -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 */
index a3a064caa3bdc55b1885b3a41de84dc2c06243b4..442749399133b433b011656ac9066f0720e10a70 100644 (file)
@@ -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
index 066cb62261222d7b32c549503b8f2dedbecefa3b..cb86767970d6878ff0d2243205f414e50c7ae64b 100644 (file)
@@ -19,3 +19,7 @@ int hal_uart_try_getc(void) {
     }
     return -1;
 }
+
+void hal_uart_set_rx_callback(void (*cb)(char)) {
+    (void)cb;
+}
index c22c91584c13a6638bc6f75e9e5067940e9efb4d..b170005633fa7359342ab80e45d52e77ae13b9e4 100644 (file)
@@ -22,3 +22,7 @@ int hal_uart_try_getc(void) {
     }
     return -1;
 }
+
+void hal_uart_set_rx_callback(void (*cb)(char)) {
+    (void)cb;
+}
index 8d7eb9ae19af55e57d3fafbd751022728901434e..231bf1b498c8a0eee60955e1d384626de1575a83 100644 (file)
@@ -20,3 +20,7 @@ int hal_uart_try_getc(void) {
     }
     return -1;
 }
+
+void hal_uart_set_rx_callback(void (*cb)(char)) {
+    (void)cb;
+}
index 37dc176707bad606e459760a0de5601a327669a8..1c5b55eab918f0ee64b8c8258c8357cd70b544ce 100644 (file)
@@ -1,18 +1,39 @@
 #include "hal/uart.h"
 #include "io.h"
+#include "arch/x86/idt.h"
 
 #include <stdint.h>
 
 #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) {
index a1029e1846f0ec2d8c854a36c4bf452501aa023a..0677b04069bb054b3dc0dc7c5317ed84d627e791 100644 (file)
@@ -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;
                 }
             }
         }
index 1118a9dca823e7bfb8e0bb3a393a345a301dc6c4..16b6c268a265651f5794ba6de19563d50d045c63 100644 (file)
@@ -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,