From dd8564a1348b8667b7a4a3cd236cc4cd4783c5e6 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 3 Jan 2020 22:13:38 +0200 Subject: [PATCH] Added a kind-of-working openpty() --- etc/make/conf.mk | 3 +- include/sys/fs/pty.h | 24 ++++++ include/sys/syscall.h | 2 + sys/amd64/hw/con.c | 4 +- sys/amd64/syscall.c | 49 +++++++++++ sys/vfs/pty.c | 148 ++++++++++++++++++++++++++++++++ usr/init.c | 7 +- usr/libc/include/bits/syscall.h | 1 + usr/libc/syscall.c | 4 + 9 files changed, 238 insertions(+), 4 deletions(-) create mode 100644 include/sys/fs/pty.h create mode 100644 sys/vfs/pty.c diff --git a/etc/make/conf.mk b/etc/make/conf.mk index 4ed7679..8578e1e 100644 --- a/etc/make/conf.mk +++ b/etc/make/conf.mk @@ -68,7 +68,8 @@ OBJS+=$(O)/sys/debug.o \ $(O)/sys/net/in.o \ $(O)/sys/net/netdev.o \ $(O)/sys/vfs/devfs.o \ - $(O)/sys/vfs/pseudo.o + $(O)/sys/vfs/pseudo.o \ + $(O)/sys/vfs/pty.o ifeq ($(VESA_ENABLE),1) OBJS+=$(O)/sys/psf.o \ diff --git a/include/sys/fs/pty.h b/include/sys/fs/pty.h new file mode 100644 index 0000000..e0f808a --- /dev/null +++ b/include/sys/fs/pty.h @@ -0,0 +1,24 @@ +#pragma once +#include "sys/fs/node.h" +#include "sys/ring.h" +#include "sys/chr.h" + +struct pty { + int number; + vnode_t *master; + vnode_t *slave; + // TODO: winsize/termios + + struct chrdev dev_master; + struct chrdev dev_slave; + + // Slave reads + // Master writes + struct ring ring_input; + // Slave writes + // Master reads + struct ring ring_output; + int owner_pid; +}; + +struct pty *pty_create(void); diff --git a/include/sys/syscall.h b/include/sys/syscall.h index 96f64fb..b67972a 100644 --- a/include/sys/syscall.h +++ b/include/sys/syscall.h @@ -18,4 +18,6 @@ #define SYSCALL_NR_EXIT 60 #define SYSCALL_NR_KILL 62 #define SYSCALL_NR_GETTIMEOFDAY 96 + +#define SYSCALL_NRX_OPENPTY 118 #define SYSCALL_NRX_SIGRET 119 diff --git a/sys/amd64/hw/con.c b/sys/amd64/hw/con.c index 4999fd5..f5a9be5 100644 --- a/sys/amd64/hw/con.c +++ b/sys/amd64/hw/con.c @@ -227,8 +227,8 @@ static void process_csi(void) { break; case 'f': // Set cursor position - y = (esc_argv[0] - 1) % con_width; - x = (esc_argv[1] - 1) % (con_height - 1); + y = (esc_argv[0] - 1) % con_height; + x = (esc_argv[1] - 1) % (con_width - 1); amd64_con_moveto(y, x); break; case 's': diff --git a/sys/amd64/syscall.c b/sys/amd64/syscall.c index db5bad4..d9267c6 100644 --- a/sys/amd64/syscall.c +++ b/sys/amd64/syscall.c @@ -12,6 +12,7 @@ #include "sys/tty.h" #include "sys/amd64/mm/phys.h" #include "sys/amd64/mm/map.h" +#include "sys/fs/pty.h" #include "sys/time.h" static ssize_t sys_read(int fd, void *buf, size_t lim); @@ -29,6 +30,9 @@ static int sys_brk(void *ptr); static int sys_nanosleep(const struct timespec *req, struct timespec *rem); static int sys_gettimeofday(struct timeval *tv, struct timezone *tz); +// TODO: const struct termios *termp, const struct winsize *winp +static int sys_openpty(int *master, int *slave); + extern int sys_execve(const char *filename, const char *const argv[], const char *const envp[]); // Non-compliant with linux style, but fuck'em, it just works @@ -80,9 +84,12 @@ intptr_t amd64_syscall(uintptr_t rdi, uintptr_t rsi, uintptr_t rdx, uintptr_t rc return sys_kill((int) rdi, (int) rsi); case SYSCALL_NR_GETTIMEOFDAY: return sys_gettimeofday((struct timeval *) rdi, (struct timezone *) rsi); + case SYSCALL_NRX_SIGRET: sys_sigret(); return 0; + case SYSCALL_NRX_OPENPTY: + return sys_openpty((int *) rdi, (int *) rsi); default: kerror("unknown syscall: %u\n", rax); @@ -208,6 +215,48 @@ static int sys_open(const char *filename, int flags, int mode) { } } +static int sys_openpty(int *master, int *slave) { + struct thread *thr = get_cpu()->thread; + _assert(thr); + // Find two free file descriptors + int fd_master = -1, fd_slave = -1; + int res; + + for (int i = 0; i < 4; ++i) { + if (!thr->fds[i].vnode) { + if (fd_master == -1) { + fd_master = i; + continue; + } + fd_slave = i; + break; + } + } + + if (fd_master == -1 || fd_slave == -1) { + return -EMFILE; + } + + struct ofile *of_master = &thr->fds[fd_master]; + struct ofile *of_slave = &thr->fds[fd_slave]; + + struct pty *pty = pty_create(); + _assert(pty); + + of_master->vnode = pty->master; + of_master->flags = O_RDWR; + of_master->pos = 0; + + of_slave->vnode = pty->slave; + of_slave->flags = O_RDWR; + of_slave->pos = 0; + + *master = fd_master; + *slave = fd_slave; + + return 0; +} + static void sys_close(int fd) { if (fd >= 4 || fd < 0) { return; diff --git a/sys/vfs/pty.c b/sys/vfs/pty.c new file mode 100644 index 0000000..01af730 --- /dev/null +++ b/sys/vfs/pty.c @@ -0,0 +1,148 @@ +#include "sys/fs/pty.h" +#include "sys/fs/ofile.h" +#include "sys/fs/node.h" +#include "sys/amd64/cpu.h" +#include "sys/string.h" +#include "sys/assert.h" +#include "sys/debug.h" +#include "sys/errno.h" +#include "sys/heap.h" + +#define PTY_RING_SIZE 256 + +static ssize_t pty_master_write(struct chrdev *dev, const void *buf, size_t count, size_t off); +static ssize_t pty_master_read(struct chrdev *dev, void *buf, size_t count, size_t off); +static ssize_t pty_slave_write(struct chrdev *dev, const void *buf, size_t count, size_t off); +static ssize_t pty_slave_read(struct chrdev *dev, void *buf, size_t count, size_t off); + +//static struct chrdev pty_master_dev = { +// .read = pty_master_read, +// .write = pty_master_write +//}; +// +//static struct chrdev pty_slave_dev = { +// .read = pty_slave_read, +// .write = pty_slave_write +//}; + +static ssize_t pty_slave_write(struct chrdev *dev, const void *buf, size_t off, size_t count) { + // Slave writes -> pty output -> Master reads + // AS-IS + struct pty *pty = dev->dev_data; + _assert(pty); + int res = 0; + + for (size_t i = 0; i < count; ++i) { + if ((res = ring_putc(&pty->ring_output, ((const char *) buf)[i])) < 0) { + break; + } + } + + return (res < 0) ? res : (ssize_t) count; +} + +static ssize_t pty_slave_read(struct chrdev *dev, void *buf, size_t off, size_t count) { + // Slave reads <- pty input <- Master writes + // TODO: process stuff like ^C/^D etc. + struct pty *pty = dev->dev_data; + _assert(pty); + char ibuf[16]; + size_t rem = count; + size_t p = 0; + + if (count == 0) { + return 0; + } + + while (rem) { + ssize_t rd = ring_read(get_cpu()->thread, &pty->ring_output, ibuf, MIN(16, rem)); + if (rd < 0) { + break; + } + memcpy((char *) buf + p, ibuf, rd); + + rem -= rd; + } + + return p; +} + +static ssize_t pty_master_write(struct chrdev *dev, const void *buf, size_t pos, size_t count) { + // Master writes -> pty input -> Slave reads + // TODO: process stuff like CR/LF conversion etc. + struct pty *pty = dev->dev_data; + _assert(pty); + int res = 0; + + for (size_t i = 0; i < count; ++i) { + if ((res = ring_putc(&pty->ring_input, ((const char *) buf)[i])) < 0) { + break; + } + } + + return (res < 0) ? res : (ssize_t) count; +} + +static ssize_t pty_master_read(struct chrdev *dev, void *buf, size_t off, size_t count) { + // Master reads <- pty output <- Slave writes + // AS-IS + struct pty *pty = dev->dev_data; + _assert(pty); + char ibuf[16]; + size_t rem = count; + size_t p = 0; + + if (count == 0) { + return 0; + } + + while (rem) { + ssize_t rd = ring_read(get_cpu()->thread, &pty->ring_output, ibuf, MIN(16, rem)); + if (rd < 0) { + break; + } + memcpy((char *) buf + p, ibuf, rd); + + rem -= rd; + } + + return p; +} + +struct pty *pty_create(void) { + struct pty *pty = kmalloc(sizeof(struct pty)); + _assert(pty); + + ring_init(&pty->ring_input, PTY_RING_SIZE); + ring_init(&pty->ring_output, PTY_RING_SIZE); + + pty->dev_master.read = pty_master_read; + pty->dev_master.write = pty_master_write; + pty->dev_master.dev_data = pty; + pty->dev_slave.read = pty_slave_read; + pty->dev_slave.write = pty_slave_write; + pty->dev_slave.dev_data = pty; + + vnode_t *pty_master = kmalloc(sizeof(vnode_t)); + _assert(pty_master); + vnode_t *pty_slave = kmalloc(sizeof(vnode_t)); + _assert(pty_slave); + + // TODO: add these to devfs + pty_master->refcount = 0; + pty_master->fs = NULL; + pty_master->tree_node = NULL; + pty_master->type = VN_CHR; + pty_master->dev = &pty->dev_master; + + pty_slave->refcount = 0; + pty_slave->fs = NULL; + pty_slave->tree_node = NULL; + pty_slave->type = VN_CHR; + pty_slave->dev = &pty->dev_slave; + + pty->master = pty_master; + pty->slave = pty_slave; + + return pty; +} diff --git a/usr/init.c b/usr/init.c index f4ee9e7..506cad0 100644 --- a/usr/init.c +++ b/usr/init.c @@ -183,7 +183,12 @@ static int b_curs(const char *arg) { while (1) { // Draw some kind of status bar curs_set(25, 1); - printf("\033[7m This is statusbar\033[K\033[0m"); + printf("\033[7m This is statusbar\033[K"); + if (c >= ' ') { + curs_set(25, 79); + printf("%c\033[0m", c); + } + printf("\033[0m"); curs_set(1, 1); if (read(STDIN_FILENO, &c, 1) < 0) { diff --git a/usr/libc/include/bits/syscall.h b/usr/libc/include/bits/syscall.h index 67e435c..7950cca 100644 --- a/usr/libc/include/bits/syscall.h +++ b/usr/libc/include/bits/syscall.h @@ -21,5 +21,6 @@ int getpid(void); int chdir(const char *filename); char *getcwd(char *buf, size_t size); int nanosleep(const struct timespec *req, struct timespec *rem); +int openpty(int *amaster, int *aslave); __attribute__((noreturn)) void exit(int code); diff --git a/usr/libc/syscall.c b/usr/libc/syscall.c index b905961..0d041c1 100644 --- a/usr/libc/syscall.c +++ b/usr/libc/syscall.c @@ -129,6 +129,10 @@ int nanosleep(const struct timespec *req, struct timespec *rem) { return SET_ERRNO(int, ASM_SYSCALL2(SYSCALL_NR_NANOSLEEP, req, rem)); } +int openpty(int *master, int *slave) { + return SET_ERRNO(int, ASM_SYSCALL2(SYSCALL_NRX_OPENPTY, master, slave)); +} + // Although sbrk() is implemented in userspace, I guess it should also be here void *sbrk(intptr_t inc) { if (inc == 0) {