diff --git a/src/arch/x86_64/serial/serial.h b/src/arch/x86_64/serial/serial.h index 4ac21ac..b5bf513 100644 --- a/src/arch/x86_64/serial/serial.h +++ b/src/arch/x86_64/serial/serial.h @@ -6,4 +6,5 @@ void serial_init(void); void serial_putchar(char ch); void serial_puts(char *str); char serial_get_byte(void); -char serial_getchar(void); \ No newline at end of file +char serial_getchar(void); +int serial_received(void); \ No newline at end of file diff --git a/src/drivers/tty/console.c b/src/drivers/tty/console.c index b8de866..4657269 100644 --- a/src/drivers/tty/console.c +++ b/src/drivers/tty/console.c @@ -9,6 +9,8 @@ #include #include #include +#include "arch/x86_64/serial/serial.h" +#include "sched/sched.h" struct console { struct resource res; @@ -19,6 +21,11 @@ struct console { struct console *console_device = NULL; +static void console_emit(char c) { + framebuffer_putchar(c); + serial_putchar(c); +} + static ssize_t console_write(struct resource *this, struct f_description *description, const void *buf, off_t offset, size_t count) { @@ -34,13 +41,114 @@ static ssize_t console_write(struct resource *this, char *r = (char *)buf; for (size_t i = 0; i < count; i++) { - framebuffer_putchar(r[i]); + console_emit(r[i]); } spinlock_drop(&this->lock); return count; } +static ssize_t console_read(struct resource *this, + struct f_description *description, void *buf, + off_t offset, size_t count) { + (void)this; + (void)description; + (void)offset; + + if (!buf) { + errno = EFAULT; + return -1; + } + + if (count == 0) { + return 0; + } + + char *out = (char *)buf; + size_t pos = 0; + + tcflag_t lflag = console_device->term.c_lflag; + tcflag_t iflag = console_device->term.c_iflag; + bool canon = (lflag & ICANON) != 0; + bool echo = (lflag & ECHO) != 0; + bool echoe = (lflag & ECHOE) != 0; + + cc_t verase = console_device->term.c_cc[VERASE]; + if (verase == 0) { + verase = 0x7f; + } + cc_t veof = console_device->term.c_cc[VEOF]; + + while (pos < count) { + while (!serial_received()) { + sched_yield(true); + } + char c = serial_get_byte(); + + // Input mode flags + if ((iflag & ISTRIP) != 0) { + c = (char)((unsigned char)c & 0x7f); + } + if ((iflag & IGNCR) != 0 && c == '\r') { + continue; + } + if ((iflag & ICRNL) != 0 && c == '\r') { + c = '\n'; + } else if ((iflag & INLCR) != 0 && c == '\n') { + c = '\r'; + } + + if (canon) { + // Backspace / VERASE handling + if (c == (char)verase || c == 0x08) { + if (pos > 0) { + pos--; + if (echo && echoe) { + console_emit('\b'); + console_emit(' '); + console_emit('\b'); + } + } + continue; + } + + // EOF: return what we have so far (possibly 0) + if (veof != 0 && c == (char)veof) { + break; + } + + out[pos++] = c; + + if (echo) { + if (c == '\n') { + console_emit('\n'); + } else if ((unsigned char)c < 0x20 && c != '\t' && + (lflag & ECHOCTL) != 0) { + console_emit('^'); + console_emit((char)(c + 0x40)); + } else { + console_emit(c); + } + } else if (c == '\n' && (lflag & ECHONL) != 0) { + console_emit('\n'); + } + + if (c == '\n') { + break; + } + } else { + // Non-canonical (raw) mode: return as soon as we have any data. + out[pos++] = c; + if (echo) { + console_emit(c); + } + break; + } + } + + return (ssize_t)pos; +} + int console_ioctl(struct resource *this, struct f_description *description, uint64_t request, uint64_t arg) { (void)description; @@ -76,6 +184,27 @@ int console_ioctl(struct resource *this, struct f_description *description, } break; } + case TIOCSWINSZ: + // Accept but ignore: the console window size is fixed by the fb. + break; + case TIOCSCTTY: + // Becoming the controlling tty is a no-op; there's only one console + // and any process opening it is implicitly attached. + break; + case TIOCGPGRP: + case TIOCGSID: { + int *n = (int *)arg; + if (n) { + *n = sched_get_running_thread()->mother_proc->pid; + } else { + errno = EINVAL; + ret = -1; + } + break; + } + case TIOCSPGRP: + // Accept but ignore: no foreground-pgrp tracking yet. + break; default: errno = EINVAL; ret = -1; @@ -141,12 +270,14 @@ void console_init(void) { console_device->res.status |= POLLOUT; + console_device->res.read = console_read; console_device->res.write = console_write; console_device->res.ioctl = console_ioctl; console_device->decckm = false; devtmpfs_add_device((struct resource *)console_device, "console"); + devtmpfs_add_device((struct resource *)console_device, "tty"); kprintffos(false, "Bye bye!\n"); framebuffer_clear(0x00eee8d5, 0); diff --git a/src/fs/elf.c b/src/fs/elf.c index ad3c63d..5e6e0b3 100644 --- a/src/fs/elf.c +++ b/src/fs/elf.c @@ -406,6 +406,9 @@ bool elf_load(struct pagemap *pagemap, struct resource *res, uint64_t load_base, return false; } + auxv->at_phdr = 0; + bool phdr_set = false; + for (size_t i = 0; i < header.e_phnum; i++) { Elf64_Phdr phdr; if (res->read(res, NULL, &phdr, header.e_phoff + i * header.e_phentsize, @@ -446,10 +449,18 @@ bool elf_load(struct pagemap *pagemap, struct resource *res, uint64_t load_base, goto fail; } + // Fallback when no PT_PHDR: if this LOAD segment covers the + // program header table, derive at_phdr from it. + if (!phdr_set && header.e_phoff >= phdr.p_offset && + header.e_phoff < phdr.p_offset + phdr.p_filesz) { + auxv->at_phdr = phdr.p_vaddr + (header.e_phoff - phdr.p_offset) + load_base; + } + break; } case PT_PHDR: auxv->at_phdr = phdr.p_vaddr + load_base; + phdr_set = true; break; case PT_INTERP: { void *path = kmalloc(phdr.p_filesz + 1); diff --git a/src/libk/debug.c b/src/libk/debug.c index 3719b28..af64f6a 100644 --- a/src/libk/debug.c +++ b/src/libk/debug.c @@ -12,6 +12,7 @@ #include "fs/elf.h" #include "sched/sched_types.h" #include "kargs.h" +#include "arch/x86_64/serial/serial.h" #if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD # define printf_ printf @@ -650,7 +651,7 @@ bool print_now = false; void kputchar(char c) { if (c == '\n') kputchar('\r'); - //kputchar_(c); + kputchar_(c); if (put_to_fb) framebuffer_putchar(c); diff --git a/src/libk/debug.h b/src/libk/debug.h index cb25c22..245b74a 100644 --- a/src/libk/debug.h +++ b/src/libk/debug.h @@ -133,6 +133,7 @@ void debug_hex_dump(const void *data, size_t size); #define log_err(module, ...) logf(module, LVL_ERROR, __VA_ARGS__) #define log_crit(module, ...) logf(module, LVL_CRITICAL, __VA_ARGS__) #define kprintf(...) kprintffos(put_to_fb, __VA_ARGS__) +#define kputchar_ serial_putchar #define putchar_ kputchar