]> 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 d5b7e8836e7e2197d9c1440ed007970ee1662f89..857fe987e9e1792084ba894c914de827a996bce4 100644 (file)
@@ -13,5 +13,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 4e0bbe9dce77e28d5dbab283f92364871f20caeb..20af75ba98a2e32c425d67a73d8793a49df86df7 100644 (file)
@@ -138,11 +138,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 d475d57e4061527eaf416b792dc8f9771011170a..e17e1a3613c3f771bcbf780ada099aadc3440fa7 100644 (file)
@@ -30,17 +30,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 a7f265af5e9418ffa8d7766788835b31d41597c3..2859502870f22c1f138b02810eac824fd861c24d 100644 (file)
@@ -28,3 +28,7 @@ int hal_uart_try_getc(void) {
     }
     return -1;
 }
+
+void hal_uart_set_rx_callback(void (*cb)(char)) {
+    (void)cb;
+}
index 77996abf3c1ac6bfaf68a4b17bba70cb019d25f4..a83417e9adce478f9c34075f4a451153e9b88908 100644 (file)
@@ -31,3 +31,7 @@ int hal_uart_try_getc(void) {
     }
     return -1;
 }
+
+void hal_uart_set_rx_callback(void (*cb)(char)) {
+    (void)cb;
+}
index a95959acc96084e60fdaf3a22f76c1ac9c2415a8..1d1a650f9198ee140373f9126575ee8e89a58ab5 100644 (file)
@@ -29,3 +29,7 @@ int hal_uart_try_getc(void) {
     }
     return -1;
 }
+
+void hal_uart_set_rx_callback(void (*cb)(char)) {
+    (void)cb;
+}
index 36325a933a09b2daf3b603060a532a9dab983266..5e80fcf8a005ca0d8045b47e130333a9288fffc7 100644 (file)
@@ -9,19 +9,40 @@
 
 #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 da62c6849a1b4da6a21eae4922125d819235c1ae..6f93f11cc4b272306b37ee0b08f746ebe5a84f7d 100644 (file)
 
 /* ---- 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];
@@ -97,17 +98,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;
@@ -154,34 +153,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
@@ -191,13 +186,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 f0484a6c8921ba2365184ed5d4278289b543fac2..c98f47be5cf8121a2ca63e812ff7c26d26b53951 100644 (file)
@@ -19,6 +19,7 @@
 #include "errno.h"
 
 #include "hal/cpu.h"
+#include "hal/uart.h"
 #include "utils.h"
 
 #define TTY_LINE_MAX 256
@@ -469,6 +470,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,