diff options
author | Ian Moffett <ian@osmora.org> | 2024-03-19 23:03:26 -0400 |
---|---|---|
committer | Ian Moffett <ian@osmora.org> | 2024-03-19 23:03:26 -0400 |
commit | 60e89b6b9cf2af1ebd7e71c8624282b9ecd79a09 (patch) | |
tree | dc61fa44be993af0e5cd82f08e0d258182d148b2 | |
parent | 4d4d412ca48802200933eb0e2b0b007855d4aa7d (diff) |
kernel: syscall: Add sys_write()
Signed-off-by: Ian Moffett <ian@osmora.org>
-rw-r--r-- | sys/include/sys/filedesc.h | 3 | ||||
-rw-r--r-- | sys/include/sys/syscall.h | 1 | ||||
-rw-r--r-- | sys/kern/kern_filedesc.c | 136 | ||||
-rw-r--r-- | sys/kern/kern_syscall.c | 2 |
4 files changed, 142 insertions, 0 deletions
diff --git a/sys/include/sys/filedesc.h b/sys/include/sys/filedesc.h index ef74fb1..df30c69 100644 --- a/sys/include/sys/filedesc.h +++ b/sys/include/sys/filedesc.h @@ -32,6 +32,7 @@ #include <sys/vnode.h> #include <sys/spinlock.h> +#include <sys/syscall.h> #include <sys/types.h> struct proc; @@ -48,6 +49,8 @@ struct filedesc { struct filedesc *fd_alloc(struct proc *td); struct filedesc *fd_from_fdnum(const struct proc *td, int fdno); void fd_close_fdnum(struct proc *td, int fdno); +ssize_t write(int fd, const void *buf, size_t count); +uint64_t sys_write(struct syscall_args *args); #endif #endif diff --git a/sys/include/sys/syscall.h b/sys/include/sys/syscall.h index b78e2ad..e75b193 100644 --- a/sys/include/sys/syscall.h +++ b/sys/include/sys/syscall.h @@ -38,6 +38,7 @@ /* Do not reorder */ enum { SYS_exit = 1, + SYS_write, __MAX_SYSCALLS }; diff --git a/sys/kern/kern_filedesc.c b/sys/kern/kern_filedesc.c index a943714..fc3d5ef 100644 --- a/sys/kern/kern_filedesc.c +++ b/sys/kern/kern_filedesc.c @@ -30,11 +30,84 @@ #include <sys/filedesc.h> #include <sys/proc.h> #include <sys/sched.h> +#include <sys/errno.h> +#include <sys/system.h> +#include <sys/syslog.h> +#include <sys/vnode.h> #include <vm/dynalloc.h> +#include <dev/vcons/vcons.h> #include <assert.h> #include <string.h> /* + * This function is a helper for write(). It creates + * a buffer and copies write data to it. + * + * @td: Current thread. + * @data: Data to copy. + * @buf_out: Pointer to buffer that will store data. + * @count: Number of bytes. + */ +static int +make_write_buf(struct proc *td, const void *data, char **buf_out, size_t count) +{ + const size_t MAX_COUNT = 0x7FFFF000; + char *buf = NULL; + + if (count > MAX_COUNT) { + return -EINVAL; + } + + buf = dynalloc(count); + + if (buf == NULL) { + return -ENOMEM; + } + + __assert(buf_out != NULL); + *buf_out = buf; + + memset(buf, 0, count); + + if (td->is_user) { + /* + * A user process called us, so we want to be careful + * and use copyin() + */ + copyin((uintptr_t)data, buf, count); + } else { + /* Can just memcpy() here */ + memcpy(buf, (char *)data, count); + } + + return 0; +} + +/* + * Helper function for write() + */ +static ssize_t +do_write(struct vnode *vp, const char *buf, size_t count) +{ + struct vops *vops = vp->vops; + int status; + + __assert(vops != NULL); + + /* Can we call the write operation? */ + if (vops->write == NULL) { + return -EACCES; + } + + /* Attempt a write */ + if ((status = vops->write(vp, buf, count)) < 0) { + return status; + } + + return count; +} + +/* * Allocate a file descriptor. * * @td: Thread to allocate from, NULL for current thread. @@ -121,3 +194,66 @@ fd_close_fdnum(struct proc *td, int fdno) dynfree(fd); td->fds[fdno] = NULL; } + +ssize_t +write(int fd, const void *buf, size_t count) +{ + struct proc *td = this_td(); + struct filedesc *desc = NULL; + struct vnode *vp = NULL; + char *in_buf = NULL; + + ssize_t ret = count; + int status; + + /* + * Create our write buffer... Memory will be allocated + * and data copied. + */ + if ((status = make_write_buf(td, buf, &in_buf, count)) != 0) { + return status; + } + + /* Is this stdout/stderr? */ + if (fd == 1 || fd == 2) { + /* TODO: Update this when we have PTYs */ + vcons_putstr(&g_syslog_screen, in_buf); + return count; + } + + desc = fd_from_fdnum(td, fd); + + /* Does this file descriptor exist */ + if (desc == NULL) { + ret = -EBADF; + goto cleanup; + } + + /* Do we have a vnode? */ + if (desc->vnode == NULL) { + ret = -EACCES; + goto cleanup; + } + + vp = desc->vnode; + status = do_write(vp, in_buf, count); + + if (status < 0) { + ret = status; + goto cleanup; + } +cleanup: + dynfree(in_buf); + return ret; +} + +/* + * arg0: int fd + * arg1: const void *buf + * arg2: count + */ +uint64_t +sys_write(struct syscall_args *args) +{ + return write(args->arg0, (void *)args->arg1, args->arg2); +} diff --git a/sys/kern/kern_syscall.c b/sys/kern/kern_syscall.c index b6e31d1..2659448 100644 --- a/sys/kern/kern_syscall.c +++ b/sys/kern/kern_syscall.c @@ -31,6 +31,7 @@ #include <sys/sched.h> #include <sys/cdefs.h> #include <sys/types.h> +#include <sys/filedesc.h> __noreturn static uint64_t sys_exit(struct syscall_args *args) @@ -41,4 +42,5 @@ sys_exit(struct syscall_args *args) uint64_t(*g_syscall_table[__MAX_SYSCALLS])(struct syscall_args *args) = { sys_exit, + sys_write, }; |