aboutsummaryrefslogtreecommitdiff
path: root/kernel/api
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/api')
-rw-r--r--kernel/api/access.c32
-rw-r--r--kernel/api/syscall.c126
2 files changed, 148 insertions, 10 deletions
diff --git a/kernel/api/access.c b/kernel/api/access.c
index 0e11b73..9a7bed0 100644
--- a/kernel/api/access.c
+++ b/kernel/api/access.c
@@ -116,8 +116,18 @@ long user_vecdup(argvec_t *uvec, char ***kvecp)
*/
long addr_perm(proc_t *p, const void *vaddr, int perm)
{
- NOT_YET_IMPLEMENTED("VM: addr_perm");
- return 0;
+ // NOT_YET_IMPLEMENTED("VM: addr_perm");
+
+ // loop through the vmareas in the process's vmmap
+ vmarea_t *vma = vmmap_lookup(p->p_vmmap, ADDR_TO_PN(vaddr));
+
+ // if the vma doesn't exist, return 0
+ if (!vma)
+ {
+ return 0;
+ }
+
+ return !!(perm & vma->vma_prot);
}
/*
@@ -131,6 +141,20 @@ long addr_perm(proc_t *p, const void *vaddr, int perm)
*/
long range_perm(proc_t *p, const void *vaddr, size_t len, int perm)
{
- NOT_YET_IMPLEMENTED("VM: range_perm");
- return 0;
+ // NOT_YET_IMPLEMENTED("VM: range_perm");
+
+ // loop through the page numbers in the range
+ size_t vfn = ADDR_TO_PN(vaddr);
+ size_t end_vfn = ADDR_TO_PN(vaddr + len);
+ for (size_t i = vfn; i < end_vfn; i++)
+ {
+ // check the permissions for each page
+ if (!addr_perm(p, PN_TO_ADDR(i), perm))
+ {
+ return 0;
+ }
+ }
+
+ // return 1 if all pages have the correct permissions
+ return 1;
}
diff --git a/kernel/api/syscall.c b/kernel/api/syscall.c
index ed771ac..e077631 100644
--- a/kernel/api/syscall.c
+++ b/kernel/api/syscall.c
@@ -69,8 +69,48 @@ void syscall_init(void) { intr_register(INTR_SYSCALL, syscall_handler); }
*/
static long sys_read(read_args_t *args)
{
- NOT_YET_IMPLEMENTED("VM: sys_read");
- return -1;
+ // NOT_YET_IMPLEMENTED("VM: sys_read");
+
+ // Initialize a read_args_t struct locally in kernel space and copy from userland args.
+ read_args_t kargs;
+ long ret = copy_from_user(&kargs, args, sizeof(kargs));
+ ERROR_OUT_RET(ret);
+
+ // Allocate a temporary buffer (a page-aligned block of n pages that are enough space to store the number of bytes to read)
+ size_t size_in_pages = (kargs.nbytes + PAGE_SIZE - 1) / PAGE_SIZE;
+ void *addr = (void *)page_alloc_n(size_in_pages);
+ if (!addr)
+ {
+ ERROR_OUT_RET(-ENOMEM);
+ }
+
+ // Call do_read() with the buffer and then copy the buffer to the userland args after the system call
+ ret = do_read(kargs.fd, addr, kargs.nbytes);
+ // if ret < 0, free the temporary buffer and return -1
+ if (ret < 0)
+ {
+ page_free_n(addr, size_in_pages);
+ ERROR_OUT_RET(ret);
+ }
+ // if read nothing, free the temporary buffer and return 0
+ if (ret == 0)
+ {
+ page_free_n(addr, size_in_pages);
+ return 0;
+ }
+
+ // copy the buffer to the userland args after the system call
+ ret = copy_to_user(kargs.buf, addr, ret);
+ // if ret < 0, free the temporary buffer and return -1
+ if (ret < 0)
+ {
+ page_free_n(addr, size_in_pages);
+ ERROR_OUT_RET(ret);
+ }
+
+ // Make sure to free the temporary buffer allocated
+ page_free_n(addr, size_in_pages);
+ return ret;
}
/*
@@ -84,8 +124,42 @@ static long sys_read(read_args_t *args)
*/
static long sys_write(write_args_t *args)
{
- NOT_YET_IMPLEMENTED("VM: sys_write");
- return -1;
+ // NOT_YET_IMPLEMENTED("VM: sys_write");
+
+ // Initialize a write_args_t struct locally in kernel space and copy from userland args.
+ write_args_t kargs;
+ long ret = copy_from_user(&kargs, args, sizeof(kargs));
+ ERROR_OUT_RET(ret);
+
+ // Allocate a temporary buffer (a page-aligned block of n pages that are enough space to store the number of bytes to write)
+ size_t size_in_pages = (kargs.nbytes + PAGE_SIZE - 1) / PAGE_SIZE;
+ void *addr = (void *)page_alloc_n(size_in_pages);
+ if (!addr)
+ {
+ ERROR_OUT_RET(-ENOMEM);
+ }
+
+ // Copy the buffer from the userland args to the temporary buffer
+ ret = copy_from_user(addr, kargs.buf, kargs.nbytes);
+ // if ret < 0, free the temporary buffer and return -1
+ if (ret < 0)
+ {
+ page_free_n(addr, size_in_pages);
+ ERROR_OUT_RET(ret);
+ }
+
+ // Call do_write() with the buffer and then copy the buffer to the userland args after the system call
+ ret = do_write(kargs.fd, addr, kargs.nbytes);
+ // if ret < 0, free the temporary buffer and return -1
+ if (ret < 0)
+ {
+ page_free_n(addr, size_in_pages);
+ ERROR_OUT_RET(ret);
+ }
+
+ // Make sure to free the temporary buffer allocated
+ page_free_n(addr, size_in_pages);
+ return ret;
}
/*
@@ -100,8 +174,48 @@ static long sys_write(write_args_t *args)
*/
static long sys_getdents(getdents_args_t *args)
{
- NOT_YET_IMPLEMENTED("VM: sys_getdents");
- return -1;
+ // NOT_YET_IMPLEMENTED("VM: sys_getdents");
+
+ // Copy the arguments from user memory
+ getdents_args_t kargs;
+ long ret = copy_from_user(&kargs, args, sizeof(kargs));
+ ERROR_OUT_RET(ret);
+
+ // Check that the count field is at least the size of a dirent_t
+ if (kargs.count < sizeof(dirent_t))
+ {
+ ERROR_OUT_RET(-EINVAL);
+ }
+
+ size_t count_read = 0;
+
+ // iterate over the directory entries
+ while (count_read * sizeof(dirent_t) <= kargs.count)
+ {
+ // read count / sizeof(dirent_t) directory entries into the provided dirp and call do_getdent
+ dirent_t d;
+ ret = do_getdent(kargs.fd, &d);
+ ERROR_OUT_RET(ret); // error check
+
+ // if read nothing, break
+ if (ret == 0)
+ {
+ break;
+ }
+ // if you read a different size than dirent_t, break
+ if (ret != sizeof(dirent_t))
+ {
+ break;
+ }
+
+ // copy the dirent_t to the userland args after the system call
+ ret = copy_to_user(kargs.dirp + count_read, &d, sizeof(dirent_t));
+ ERROR_OUT_RET(ret); // error check
+
+ count_read++;
+ }
+
+ return count_read * sizeof(dirent_t);
}
#ifdef __MOUNTING__