Rough PTY support (needs work)

This commit is contained in:
Kevin Lange 2013-03-17 16:34:23 -07:00
parent cef1d359a1
commit e02cf79e2a
6 changed files with 285 additions and 11 deletions

266
kernel/fs/tty.c Normal file
View File

@ -0,0 +1,266 @@
#include <system.h>
#include <fs.h>
#include <pipe.h>
#include <logging.h>
#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;
}

View File

@ -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();

View File

@ -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 */

View File

@ -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);

View File

@ -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);

View File

@ -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