Added a kind-of-working openpty()
This commit is contained in:
+2
-1
@@ -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 \
|
||||
|
||||
@@ -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);
|
||||
@@ -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
|
||||
|
||||
+2
-2
@@ -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':
|
||||
|
||||
@@ -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;
|
||||
|
||||
+148
@@ -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;
|
||||
}
|
||||
+6
-1
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user