From: Tulio A M Mendes Date: Sat, 7 Feb 2026 19:34:05 +0000 (-0300) Subject: tty: add canonical line discipline and wire fd 0/1/2 X-Git-Url: https://projects.tadryanom.me/?a=commitdiff_plain;h=a20bc1a1f2d23bffa67cf38609e801799e677e33;p=AdrOS.git tty: add canonical line discipline and wire fd 0/1/2 --- diff --git a/include/kernel/init.h b/include/kernel/init.h index 0aee3c4..b5fe3a3 100644 --- a/include/kernel/init.h +++ b/include/kernel/init.h @@ -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 index 0000000..c3cb136 --- /dev/null +++ b/include/tty.h @@ -0,0 +1,14 @@ +#ifndef TTY_H +#define TTY_H + +#include +#include + +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 diff --git a/src/kernel/init.c b/src/kernel/init.c index d463a41..8047268 100644 --- a/src/kernel/init.c +++ b/src/kernel/init.c @@ -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; } diff --git a/src/kernel/main.c b/src/kernel/main.c index dbe975e..cf477f3 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -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"); diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 2b228c5..f283505 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -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 index 0000000..24b1b2d --- /dev/null +++ b/src/kernel/tty.c @@ -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(); + } +}