diff options
author | Ian Moffett <ian@osmora.org> | 2024-03-26 18:26:16 -0400 |
---|---|---|
committer | Ian Moffett <ian@osmora.org> | 2024-03-26 18:26:16 -0400 |
commit | 54224fb3d937811de957d51596602c0f2afc5fbe (patch) | |
tree | f8f3b28a74dacd2bbbbc61f20afa52c455905b56 | |
parent | 42ad59bdb6df99ccd146d6d67cb8c838be709ec5 (diff) |
kernel: Add initial read() implementation
Signed-off-by: Ian Moffett <ian@osmora.org>
-rw-r--r-- | sys/include/sys/filedesc.h | 2 | ||||
-rw-r--r-- | sys/include/sys/syscall.h | 1 | ||||
-rw-r--r-- | sys/kern/kern_filedesc.c | 67 | ||||
-rw-r--r-- | sys/kern/kern_syscall.c | 1 |
4 files changed, 71 insertions, 0 deletions
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 @@ -298,6 +298,36 @@ open(const char *pathname, int oflag) } /* + * 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 * arg2: count @@ -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, }; |