diff options
Diffstat (limited to 'kernel/api')
-rw-r--r-- | kernel/api/access.c | 32 | ||||
-rw-r--r-- | kernel/api/syscall.c | 126 |
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__ |