summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/include/sys/filedesc.h3
-rw-r--r--sys/include/sys/syscall.h1
-rw-r--r--sys/kern/kern_filedesc.c136
-rw-r--r--sys/kern/kern_syscall.c2
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,
};