From e02cf79e2a9048630954ef8a7c27cebf2d47bb24 Mon Sep 17 00:00:00 2001 From: Kevin Lange Date: Sun, 17 Mar 2013 16:34:23 -0700 Subject: [PATCH] Rough PTY support (needs work) --- kernel/fs/tty.c | 266 +++++++++++++++++++++ kernel/include/fs.h | 1 + kernel/sys/syscall.c | 2 +- toolchain/patches/newlib/include/syscall.h | 1 + toolchain/patches/newlib/toaru/syscalls.c | 2 +- userspace/gui/terminal/terminal.c | 24 +- 6 files changed, 285 insertions(+), 11 deletions(-) create mode 100644 kernel/fs/tty.c diff --git a/kernel/fs/tty.c b/kernel/fs/tty.c new file mode 100644 index 00000000..d55e06bf --- /dev/null +++ b/kernel/fs/tty.c @@ -0,0 +1,266 @@ +#include +#include +#include +#include + +#define TTY_BUFFER_SIZE 512 + +struct winsize { + unsigned short row, col, pix_w, pix_h; +}; + +typedef struct { + uint8_t * buffer; + size_t write_ptr; + size_t read_ptr; + size_t size; + uint8_t volatile lock; + list_t * wait_queue; +} ring_buffer_t; + +typedef struct pty { + int name; + fs_node_t * master; + fs_node_t * slave; + struct winsize size; + + ring_buffer_t in; + ring_buffer_t out; +} pty_t; + +list_t * pty_list = NULL; + +static inline size_t ring_buffer_unread(ring_buffer_t * ring_buffer) { + if (ring_buffer->read_ptr == ring_buffer->write_ptr) { + return 0; + } + if (ring_buffer->read_ptr > ring_buffer->write_ptr) { + return (ring_buffer->size - ring_buffer->read_ptr) + ring_buffer->write_ptr; + } else { + return (ring_buffer->write_ptr - ring_buffer->read_ptr); + } +} + +size_t ring_buffer_size(fs_node_t * node) { + ring_buffer_t * ring_buffer = (ring_buffer_t *)node->inode; + return ring_buffer_unread(ring_buffer); +} + +static inline size_t ring_buffer_available(ring_buffer_t * ring_buffer) { + if (ring_buffer->read_ptr == ring_buffer->write_ptr) { + return ring_buffer->size - 1; + } + + if (ring_buffer->read_ptr > ring_buffer->write_ptr) { + return ring_buffer->read_ptr - ring_buffer->write_ptr - 1; + } else { + return (ring_buffer->size - ring_buffer->write_ptr) + ring_buffer->read_ptr - 1; + } +} + +static inline void ring_buffer_increment_read(ring_buffer_t * ring_buffer) { + ring_buffer->read_ptr++; + if (ring_buffer->read_ptr == ring_buffer->size) { + ring_buffer->read_ptr = 0; + } +} + +static inline void ring_buffer_increment_write(ring_buffer_t * ring_buffer) { + ring_buffer->write_ptr++; + if (ring_buffer->write_ptr == ring_buffer->size) { + ring_buffer->write_ptr = 0; + } +} + + +uint32_t read_pty_master(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) { + pty_t * pty = (pty_t *)node->inode; + + /* Standard pipe read */ + size_t collected = 0; + while (collected == 0) { + spin_lock(&pty->out.lock); + while (ring_buffer_unread(&pty->out) > 0 && collected < size) { + buffer[collected] = pty->out.buffer[pty->out.read_ptr]; + ring_buffer_increment_read(&pty->out); + collected++; + } + spin_unlock(&pty->out.lock); + wakeup_queue(pty->out.wait_queue); + if (collected == 0) { + sleep_on(pty->out.wait_queue); + } + } + + return collected; +} +uint32_t write_pty_master(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) { + pty_t * pty = (pty_t *)node->inode; + + size_t written = 0; + while (written < size) { + spin_lock(&pty->in.lock); + + while (ring_buffer_available(&pty->in) > 0 && written < size) { + pty->in.buffer[pty->in.write_ptr] = buffer[written]; + ring_buffer_increment_write(&pty->in); + written++; + } + + spin_unlock(&pty->in.lock); + wakeup_queue(pty->in.wait_queue); + if (written < size) { + sleep_on(pty->in.wait_queue); + } + } + + return written; +} +void open_pty_master(fs_node_t * node, uint8_t read, uint8_t write) { + return; +} +void close_pty_master(fs_node_t * node) { + return; +} + +uint32_t read_pty_slave(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) { + pty_t * pty = (pty_t *)node->inode; + + /* Standard pipe read */ + size_t collected = 0; + while (collected == 0) { + spin_lock(&pty->in.lock); + while (ring_buffer_unread(&pty->in) > 0 && collected < size) { + buffer[collected] = pty->in.buffer[pty->in.read_ptr]; + ring_buffer_increment_read(&pty->in); + collected++; + } + spin_unlock(&pty->in.lock); + wakeup_queue(pty->in.wait_queue); + if (collected == 0) { + sleep_on(pty->in.wait_queue); + } + } + + return collected; +} +uint32_t write_pty_slave(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) { + pty_t * pty = (pty_t *)node->inode; + + size_t written = 0; + while (written < size) { + spin_lock(&pty->out.lock); + + while (ring_buffer_available(&pty->out) > 0 && written < size) { + pty->out.buffer[pty->out.write_ptr] = buffer[written]; + ring_buffer_increment_write(&pty->out); + written++; + } + + spin_unlock(&pty->out.lock); + wakeup_queue(pty->out.wait_queue); + if (written < size) { + sleep_on(pty->out.wait_queue); + } + } + + return written; +} +void open_pty_slave(fs_node_t * node, uint8_t read, uint8_t write) { + return; +} +void close_pty_slave(fs_node_t * node) { + return; +} + +fs_node_t * pty_master_create(pty_t * pty) { + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + + fnode->name[0] = '\0'; + sprintf(fnode->name, "pty master"); + fnode->uid = 0; + fnode->gid = 0; + fnode->flags = FS_PIPE; + fnode->read = read_pty_master; + fnode->write = write_pty_master; + fnode->open = open_pty_master; + fnode->close = close_pty_master; + fnode->readdir = NULL; + fnode->finddir = NULL; + + fnode->inode = (uintptr_t)pty; + + return fnode; +} + +fs_node_t * pty_slave_create(pty_t * pty) { + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + + fnode->name[0] = '\0'; + sprintf(fnode->name, "pty slave"); + fnode->uid = 0; + fnode->gid = 0; + fnode->flags = FS_PIPE; + fnode->read = read_pty_slave; + fnode->write = write_pty_slave; + fnode->open = open_pty_slave; + fnode->close = close_pty_slave; + fnode->readdir = NULL; + fnode->finddir = NULL; + + fnode->inode = (uintptr_t)pty; + + return fnode; +} + +void pty_install(void) { + pty_list = list_create(); +} + +pty_t * pty_new(struct winsize * size) { + pty_t * pty = malloc(sizeof(pty_t)); + + pty->in.buffer = malloc(TTY_BUFFER_SIZE); + pty->in.write_ptr = 0; + pty->in.read_ptr = 0; + pty->in.lock = 0; + pty->in.size = TTY_BUFFER_SIZE; + pty->in.wait_queue = list_create(); + + pty->out.buffer = malloc(TTY_BUFFER_SIZE); + pty->out.write_ptr = 0; + pty->out.read_ptr = 0; + pty->out.lock = 0; + pty->out.wait_queue = list_create(); + pty->out.size = TTY_BUFFER_SIZE; + + pty->master = pty_master_create(pty); + pty->slave = pty_slave_create(pty); + + list_insert(pty_list, pty); + pty->name = list_index_of(pty_list, pty); + + if (size) { + memcpy(&pty->size, size, sizeof(struct winsize)); + } else { + /* Sane defaults */ + pty->size.row = 25; + pty->size.col = 80; + } + return pty; +} + +int openpty(int * master, int * slave, char * name, void * _ign0, void * size) { + if (!master || !slave) return -1; + + pty_t * pty = pty_new(size); + + *master = process_append_fd((process_t *)current_process, pty->master); + *slave = process_append_fd((process_t *)current_process, pty->slave); + + return 0; +} + + diff --git a/kernel/include/fs.h b/kernel/include/fs.h index 514ec2cf..934a4a5b 100644 --- a/kernel/include/fs.h +++ b/kernel/include/fs.h @@ -87,6 +87,7 @@ extern fs_node_t *fs_root; extern fs_node_t * null_device_create(); extern fs_node_t * serial_device_create(int device); extern void serial_mount_devices(); +extern int openpty(int * master, int * slave, char * name, void * _ign0, void * size); extern fs_node_t * hello_device_create(); diff --git a/kernel/sys/syscall.c b/kernel/sys/syscall.c index c6b983ae..71287e53 100644 --- a/kernel/sys/syscall.c +++ b/kernel/sys/syscall.c @@ -605,7 +605,7 @@ static uintptr_t syscalls[] = { (uintptr_t)&sys_sbrk, (uintptr_t)&getgraphicsaddress, (uintptr_t)&uname, /* 12 */ - (uintptr_t)RESERVED, + (uintptr_t)&openpty, (uintptr_t)&seek, (uintptr_t)&stat, (uintptr_t)&setgraphicsoffset, /* 16 */ diff --git a/toolchain/patches/newlib/include/syscall.h b/toolchain/patches/newlib/include/syscall.h index c3707df0..39010c80 100644 --- a/toolchain/patches/newlib/include/syscall.h +++ b/toolchain/patches/newlib/include/syscall.h @@ -61,6 +61,7 @@ DECL_SYSCALL0(getpid); DECL_SYSCALL1(sbrk, int); DECL_SYSCALL0(getgraphicsaddress); DECL_SYSCALL1(uname, void *); +DECL_SYSCALL5(openpty, int *, int *, char *, void *, void *); DECL_SYSCALL3(lseek, int, int, int); DECL_SYSCALL2(fstat, int, void *); DECL_SYSCALL1(setgraphicsoffset, int); diff --git a/toolchain/patches/newlib/toaru/syscalls.c b/toolchain/patches/newlib/toaru/syscalls.c index 39f4001c..237961e3 100644 --- a/toolchain/patches/newlib/toaru/syscalls.c +++ b/toolchain/patches/newlib/toaru/syscalls.c @@ -36,7 +36,7 @@ DEFN_SYSCALL0(getpid, 9); DEFN_SYSCALL1(sbrk, 10, int); DEFN_SYSCALL0(getgraphicsaddress, 11); DEFN_SYSCALL1(uname, 12, void *); -/* RESERVED syscall 13 */ +DEFN_SYSCALL5(openpty, 13, int *, int *, char *, void *, void *); DEFN_SYSCALL3(lseek, 14, int, int, int); DEFN_SYSCALL2(fstat, 15, int, void *); DEFN_SYSCALL1(setgraphicsoffset, 16, int); diff --git a/userspace/gui/terminal/terminal.c b/userspace/gui/terminal/terminal.c index 3ecb150a..5f77e3bf 100644 --- a/userspace/gui/terminal/terminal.c +++ b/userspace/gui/terminal/terminal.c @@ -72,6 +72,7 @@ typedef struct _terminal_cell { * we read from ofd and write to ifd, so make sure you don't * get them backwards. */ static int ofd, ifd; +static int fd_master, fd_slave; int scale_fonts = 0; /* Whether fonts should be scaled */ float font_scaling = 1.0; /* How much they should be scaled by */ @@ -217,7 +218,7 @@ void (*redraw_cursor)(void) = NULL; * Useful for things like the ANSI DSR command. */ void input_buffer_stuff(char * str) { size_t s = strlen(str); - write(ifd, str, s); + write(fd_master, str, s); } /* Write the contents of the buffer, as they were all non-escaped data. */ @@ -1343,10 +1344,10 @@ int buffer_put(char c) { void handle_input(char c) { if (_unbuffered) { - write(ifd, &c, 1); + write(fd_master, &c, 1); } else { if (buffer_put(c)) { - write(ifd, input_buffer, input_collected); + write(fd_master, input_buffer, input_collected); clear_input(); } } @@ -1717,16 +1718,21 @@ int main(int argc, char ** argv) { reinit(); + /* ofd = syscall_mkpipe(); ifd = syscall_mkpipe(); + */ + + syscall_openpty(&fd_master, &fd_slave, NULL, NULL, NULL); + int pid = getpid(); uint32_t f = fork(); if (getpid() != pid) { - syscall_dup2(ifd, 0); - syscall_dup2(ofd, 1); - syscall_dup2(ofd, 2); + syscall_dup2(fd_slave, 0); + syscall_dup2(fd_slave, 1); + syscall_dup2(fd_slave, 2); if (argv[optind] != NULL) { char * tokens[] = {argv[optind], NULL}; @@ -1754,7 +1760,7 @@ int main(int argc, char ** argv) { if (!_windowed || _force_kernel) { /* Request kernel output to this terminal */ - syscall_system_function(4, (char **)ofd); + syscall_system_function(4, (char **)fd_slave); } child_pid = f; @@ -1774,9 +1780,9 @@ int main(int argc, char ** argv) { flip_cursor(); } - fstat(ofd, &_stat); + fstat(fd_master, &_stat); if (_stat.st_size) { - int r = read(ofd, buf, min(_stat.st_size, 1024)); + int r = read(fd_master, buf, min(_stat.st_size, 1024)); for (uint32_t i = 0; i < r; ++i) { ansi_put(buf[i]); #if DEBUG_TERMINAL_WITH_SERIAL