From 54224fb3d937811de957d51596602c0f2afc5fbe Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Tue, 26 Mar 2024 18:26:16 -0400
Subject: kernel: Add initial read() implementation

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/include/sys/filedesc.h |  2 ++
 sys/include/sys/syscall.h  |  1 +
 sys/kern/kern_filedesc.c   | 67 ++++++++++++++++++++++++++++++++++++++++++++++
 sys/kern/kern_syscall.c    |  1 +
 4 files changed, 71 insertions(+)

(limited to 'sys')

diff --git a/sys/include/sys/filedesc.h b/sys/include/sys/filedesc.h
index e0835a5..70b297d 100644
--- a/sys/include/sys/filedesc.h
+++ b/sys/include/sys/filedesc.h
@@ -55,10 +55,12 @@ 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);
 int open(const char *pathname, int oflag);
+int read(int fd, void *buf, size_t count);
 
 uint64_t sys_write(struct syscall_args *args);
 uint64_t sys_open(struct syscall_args *args);
 uint64_t sys_close(struct syscall_args *args);
+uint64_t sys_read(struct syscall_args *args);
 #endif
 
 #endif
diff --git a/sys/include/sys/syscall.h b/sys/include/sys/syscall.h
index 5020d3a..ae2438f 100644
--- a/sys/include/sys/syscall.h
+++ b/sys/include/sys/syscall.h
@@ -41,6 +41,7 @@ enum {
     SYS_write,
     SYS_open,
     SYS_close,
+    SYS_read,
     __MAX_SYSCALLS
 };
 
diff --git a/sys/kern/kern_filedesc.c b/sys/kern/kern_filedesc.c
index 6f59508..c610747 100644
--- a/sys/kern/kern_filedesc.c
+++ b/sys/kern/kern_filedesc.c
@@ -297,6 +297,36 @@ open(const char *pathname, int oflag)
     return fd->fdno;
 }
 
+/*
+ * Read file into a buffer.
+ *
+ * @fd: File descriptor number.
+ * @buf: Buffer to read to.
+ * @count: Number of bytes to read.
+ */
+int
+read(int fd, void *buf, size_t count)
+{
+    ssize_t bytes_read;
+    struct vnode *vnode;
+    struct filedesc *fd_desc;
+
+    fd_desc = fd_from_fdnum(this_td(), fd);
+
+    if (fd_desc == NULL) {
+        return -EBADF;
+    }
+
+    vnode = fd_desc->vnode;
+
+    if (count > MAX_RW_SIZE) {
+        return -EINVAL;
+    }
+
+    bytes_read = vfs_read(vnode, buf, count);
+    return bytes_read;
+}
+
 /*
  * arg0: int fd
  * arg1: const void *buf
@@ -340,3 +370,40 @@ sys_close(struct syscall_args *args)
     fd_close_fdnum(this_td(), args->arg0);
     return 0;
 }
+
+/*
+ * arg0: fd
+ * arg1: char *buf
+ * arg2: size_t count
+ */
+uint64_t
+sys_read(struct syscall_args *args)
+{
+    char *kbuf;
+    ssize_t bytes_read;
+
+    if (args->arg2 > MAX_RW_SIZE || args->arg2 == 0) {
+        return -EINVAL;
+    }
+
+    kbuf = dynalloc(args->arg2);
+
+    if (kbuf == NULL) {
+        return -ENOMEM;
+    }
+
+    /*
+     * Try to read into our kernel buffer then copy out
+     * to userspace.
+     */
+    if ((bytes_read = read(args->arg0, kbuf, args->arg2)) < 0) {
+        /* Failure */
+        dynfree(kbuf);
+        return bytes_read;
+    }
+
+    if (copyout(kbuf, args->arg1, bytes_read) != 0) {
+        invalid_uaddr(args->arg1);
+    }
+    return bytes_read;
+}
diff --git a/sys/kern/kern_syscall.c b/sys/kern/kern_syscall.c
index 4acfdc5..0f45469 100644
--- a/sys/kern/kern_syscall.c
+++ b/sys/kern/kern_syscall.c
@@ -45,4 +45,5 @@ uint64_t(*g_syscall_table[__MAX_SYSCALLS])(struct syscall_args *args) = {
     sys_write,
     sys_open,
     sys_close,
+    sys_read,
 };
-- 
cgit v1.2.3