]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
tty: add canonical line discipline and wire fd 0/1/2
authorTulio A M Mendes <[email protected]>
Sat, 7 Feb 2026 19:34:05 +0000 (16:34 -0300)
committerTulio A M Mendes <[email protected]>
Sat, 7 Feb 2026 19:34:05 +0000 (16:34 -0300)
include/kernel/init.h
include/tty.h [new file with mode: 0644]
src/kernel/init.c
src/kernel/main.c
src/kernel/syscall.c
src/kernel/tty.c [new file with mode: 0644]

index 0aee3c446fca4dbeab016a3cd5d00430e83c21a2..b5fe3a32e4d56835283d423663eade28bae551fe 100644 (file)
@@ -3,6 +3,6 @@
 
 #include "kernel/boot_info.h"
 
-void init_start(const struct boot_info* bi);
+int init_start(const struct boot_info* bi);
 
 #endif
diff --git a/include/tty.h b/include/tty.h
new file mode 100644 (file)
index 0000000..c3cb136
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef TTY_H
+#define TTY_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+void tty_init(void);
+
+int tty_read(void* user_buf, uint32_t len);
+int tty_write(const void* user_buf, uint32_t len);
+
+void tty_input_char(char c);
+
+#endif
index d463a41398f6d84aa7f7bacc108922f4294440d7..8047268ec6b55e7a4c0c298ac18c7822e36c5984 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "fs.h"
 #include "initrd.h"
+#include "tty.h"
 #include "uart_console.h"
 
 #include "hal/mm.h"
@@ -30,7 +31,7 @@ static int cmdline_has_token(const char* cmdline, const char* token) {
     return 0;
 }
 
-void init_start(const struct boot_info* bi) {
+int init_start(const struct boot_info* bi) {
     if (bi && bi->initrd_start) {
         uintptr_t initrd_virt = 0;
         if (hal_mm_map_physical_range((uintptr_t)bi->initrd_start, (uintptr_t)bi->initrd_end,
@@ -41,9 +42,13 @@ void init_start(const struct boot_info* bi) {
         }
     }
 
-    (void)arch_platform_start_userspace(bi);
+    tty_init();
+
+    int user_ret = arch_platform_start_userspace(bi);
 
     if (bi && cmdline_has_token(bi->cmdline, "ring3")) {
         arch_platform_usermode_test_start();
     }
+
+    return user_ret;
 }
index dbe975e4cef52acf977f6cc774a19d8515e2814f..cf477f3381046856f353d88fd46e081b1c1968c3 100644 (file)
@@ -59,10 +59,12 @@ void kernel_main(const struct boot_info* bi) {
 
     hal_cpu_enable_interrupts();
 
-    init_start(bi);
+    int init_ret = init_start(bi);
     
-    // Start Shell as the main interaction loop
-    shell_init();
+    if (init_ret < 0) {
+        // Start Shell as the main interaction loop
+        shell_init();
+    }
     
 done:
     uart_print("Welcome to AdrOS (x86/ARM/RISC-V/MIPS)!\n");
index 2b228c5a113170464ad3dc82d286ab74ca546f6c..f283505e57e54cff497829fa2c1d29b3ebd13820 100644 (file)
@@ -2,8 +2,7 @@
 #include "idt.h"
 #include "fs.h"
 #include "heap.h"
-#include "keyboard.h"
-#include "keyboard.h"
+#include "tty.h"
 #include "process.h"
 #include "uart_console.h"
 #include "uaccess.h"
@@ -84,13 +83,7 @@ static int syscall_read_impl(int fd, void* user_buf, uint32_t len) {
     if (user_range_ok(user_buf, (size_t)len) == 0) return -1;
 
     if (fd == 0) {
-        char kbuf[256];
-        uint32_t chunk = len;
-        if (chunk > sizeof(kbuf)) chunk = (uint32_t)sizeof(kbuf);
-        int rd = keyboard_read_blocking(kbuf, chunk);
-        if (rd <= 0) return -1;
-        if (copy_to_user(user_buf, kbuf, (size_t)rd) < 0) return -1;
-        return rd;
+        return tty_read(user_buf, len);
     }
 
     if (fd == 1 || fd == 2) return -1;
@@ -133,38 +126,7 @@ static void syscall_handler(struct registers* regs) {
             return;
         }
 
-        if (len > 1024 * 1024) {
-            regs->eax = (uint32_t)-1;
-            return;
-        }
-
-        if (user_range_ok(buf, (size_t)len) == 0) {
-            regs->eax = (uint32_t)-1;
-            return;
-        }
-
-        char kbuf[256];
-        uint32_t remaining = len;
-        uintptr_t up = (uintptr_t)buf;
-
-        while (remaining) {
-            uint32_t chunk = remaining;
-            if (chunk > sizeof(kbuf)) chunk = (uint32_t)sizeof(kbuf);
-
-            if (copy_from_user(kbuf, (const void*)up, (size_t)chunk) < 0) {
-                regs->eax = (uint32_t)-1;
-                return;
-            }
-
-            for (uint32_t i = 0; i < chunk; i++) {
-                uart_put_char(kbuf[i]);
-            }
-
-            up += chunk;
-            remaining -= chunk;
-        }
-
-        regs->eax = len;
+        regs->eax = (uint32_t)tty_write(buf, len);
         return;
     }
 
diff --git a/src/kernel/tty.c b/src/kernel/tty.c
new file mode 100644 (file)
index 0000000..24b1b2d
--- /dev/null
@@ -0,0 +1,191 @@
+#include "tty.h"
+
+#include "keyboard.h"
+#include "process.h"
+#include "spinlock.h"
+#include "uart_console.h"
+#include "uaccess.h"
+
+#define TTY_LINE_MAX 256
+#define TTY_CANON_BUF 1024
+#define TTY_WAITQ_MAX 16
+
+static spinlock_t tty_lock = {0};
+
+static char line_buf[TTY_LINE_MAX];
+static uint32_t line_len = 0;
+
+static char canon_buf[TTY_CANON_BUF];
+static uint32_t canon_head = 0;
+static uint32_t canon_tail = 0;
+
+static struct process* waitq[TTY_WAITQ_MAX];
+static uint32_t waitq_head = 0;
+static uint32_t waitq_tail = 0;
+
+static int canon_empty(void) {
+    return canon_head == canon_tail;
+}
+
+static uint32_t canon_count(void) {
+    if (canon_head >= canon_tail) return canon_head - canon_tail;
+    return (TTY_CANON_BUF - canon_tail) + canon_head;
+}
+
+static void canon_push(char c) {
+    uint32_t next = (canon_head + 1U) % TTY_CANON_BUF;
+    if (next == canon_tail) {
+        canon_tail = (canon_tail + 1U) % TTY_CANON_BUF;
+    }
+    canon_buf[canon_head] = c;
+    canon_head = next;
+}
+
+static int waitq_empty(void) {
+    return waitq_head == waitq_tail;
+}
+
+static int waitq_push(struct process* p) {
+    uint32_t next = (waitq_head + 1U) % TTY_WAITQ_MAX;
+    if (next == waitq_tail) return -1;
+    waitq[waitq_head] = p;
+    waitq_head = next;
+    return 0;
+}
+
+static struct process* waitq_pop(void) {
+    if (waitq_empty()) return NULL;
+    struct process* p = waitq[waitq_tail];
+    waitq_tail = (waitq_tail + 1U) % TTY_WAITQ_MAX;
+    return p;
+}
+
+static void tty_wake_one(void) {
+    struct process* p = waitq_pop();
+    if (p && p->state == PROCESS_BLOCKED) {
+        p->state = PROCESS_READY;
+    }
+}
+
+void tty_input_char(char c) {
+    uintptr_t flags = spin_lock_irqsave(&tty_lock);
+
+    if (c == '\b') {
+        if (line_len > 0) {
+            line_len--;
+            uart_print("\b \b");
+        }
+        spin_unlock_irqrestore(&tty_lock, flags);
+        return;
+    }
+
+    if (c == '\r') c = '\n';
+
+    if (c == '\n') {
+        uart_put_char('\n');
+
+        for (uint32_t i = 0; i < line_len; i++) {
+            canon_push(line_buf[i]);
+        }
+        canon_push('\n');
+        line_len = 0;
+
+        tty_wake_one();
+        spin_unlock_irqrestore(&tty_lock, flags);
+        return;
+    }
+
+    if (c >= ' ' && c <= '~') {
+        if (line_len + 1 < sizeof(line_buf)) {
+            line_buf[line_len++] = c;
+            uart_put_char(c);
+        }
+    }
+
+    spin_unlock_irqrestore(&tty_lock, flags);
+}
+
+static void tty_keyboard_cb(char c) {
+    tty_input_char(c);
+}
+
+void tty_init(void) {
+    spinlock_init(&tty_lock);
+    line_len = 0;
+    canon_head = canon_tail = 0;
+    waitq_head = waitq_tail = 0;
+
+    keyboard_set_callback(tty_keyboard_cb);
+}
+
+int tty_write(const void* user_buf, uint32_t len) {
+    if (!user_buf) return -1;
+    if (len > 1024 * 1024) return -1;
+    if (user_range_ok(user_buf, (size_t)len) == 0) return -1;
+
+    char kbuf[256];
+    uint32_t remaining = len;
+    uintptr_t up = (uintptr_t)user_buf;
+
+    while (remaining) {
+        uint32_t chunk = remaining;
+        if (chunk > sizeof(kbuf)) chunk = (uint32_t)sizeof(kbuf);
+
+        if (copy_from_user(kbuf, (const void*)up, (size_t)chunk) < 0) return -1;
+
+        for (uint32_t i = 0; i < chunk; i++) {
+            uart_put_char(kbuf[i]);
+        }
+
+        up += chunk;
+        remaining -= chunk;
+    }
+
+    return (int)len;
+}
+
+int tty_read(void* user_buf, uint32_t len) {
+    if (!user_buf) return -1;
+    if (len > 1024 * 1024) return -1;
+    if (user_range_ok(user_buf, (size_t)len) == 0) return -1;
+    if (!current_process) return -1;
+
+    while (1) {
+        uintptr_t flags = spin_lock_irqsave(&tty_lock);
+
+        if (!canon_empty()) {
+            uint32_t avail = canon_count();
+            uint32_t to_read = len;
+            if (to_read > avail) to_read = avail;
+
+            char kbuf[256];
+            uint32_t total = 0;
+            while (total < to_read) {
+                uint32_t chunk = to_read - total;
+                if (chunk > sizeof(kbuf)) chunk = (uint32_t)sizeof(kbuf);
+
+                for (uint32_t i = 0; i < chunk; i++) {
+                    kbuf[i] = canon_buf[canon_tail];
+                    canon_tail = (canon_tail + 1U) % TTY_CANON_BUF;
+                }
+
+                spin_unlock_irqrestore(&tty_lock, flags);
+
+                if (copy_to_user((uint8_t*)user_buf + total, kbuf, (size_t)chunk) < 0) return -1;
+
+                total += chunk;
+                flags = spin_lock_irqsave(&tty_lock);
+            }
+
+            spin_unlock_irqrestore(&tty_lock, flags);
+            return (int)to_read;
+        }
+
+        if (waitq_push(current_process) == 0) {
+            current_process->state = PROCESS_BLOCKED;
+        }
+
+        spin_unlock_irqrestore(&tty_lock, flags);
+        schedule();
+    }
+}