From 60e89b6b9cf2af1ebd7e71c8624282b9ecd79a09 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Tue, 19 Mar 2024 23:03:26 -0400 Subject: kernel: syscall: Add sys_write() Signed-off-by: Ian Moffett --- sys/kern/kern_filedesc.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++ sys/kern/kern_syscall.c | 2 + 2 files changed, 138 insertions(+) (limited to 'sys/kern') 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,10 +30,83 @@ #include #include #include +#include +#include +#include +#include #include +#include #include #include +/* + * 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. * @@ -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 #include #include +#include __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, }; -- cgit v1.2.3