diff options
author | sotech117 <michael_foiani@brown.edu> | 2024-05-13 09:27:24 +0000 |
---|---|---|
committer | sotech117 <michael_foiani@brown.edu> | 2024-05-13 09:27:24 +0000 |
commit | f09878f6327426631d9419d825a4e8396e3b9dc4 (patch) | |
tree | 009d1f1b1386baf6d07b3b7d9a436590ada14094 /kernel/vm/mmap.c | |
parent | 0e2acbe54e5800621692c2f6e9e9590aa369e165 (diff) |
weenix
Diffstat (limited to 'kernel/vm/mmap.c')
-rw-r--r-- | kernel/vm/mmap.c | 165 |
1 files changed, 161 insertions, 4 deletions
diff --git a/kernel/vm/mmap.c b/kernel/vm/mmap.c index 082149b..78aa3b5 100644 --- a/kernel/vm/mmap.c +++ b/kernel/vm/mmap.c @@ -55,8 +55,134 @@ long do_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off, void **ret) { - NOT_YET_IMPLEMENTED("VM: do_mmap"); - return -1; + // NOT_YET_IMPLEMENTED("VM: do_mmap"); + + // check if addr is page aligned when MAP_FIXED is specified + if (PAGE_ALIGNED(addr) == 0 && (flags & MAP_FIXED)) + { + return -EINVAL; + } + + // check if MAP_FIXED is specified and addr is out of range of the user address space + if ((flags & MAP_FIXED) && ((uintptr_t)addr < USER_MEM_LOW || (uintptr_t)addr + len > USER_MEM_HIGH)) + { + return -EINVAL; + } + + // check if len is not zero (len is an unsigned value, so it is always positive) + if (len == 0) + { + return -EINVAL; + } + + // check if offset is positive and aligned + if (off < 0 || PAGE_ALIGNED(off) == 0) + { + return -EINVAL; + } + + // check if flags do not contain MAP_PRIVATE or MAP_SHARED + if ((flags & MAP_PRIVATE) == 0 && (flags & MAP_SHARED) == 0) + { + return -EINVAL; + } + + // check if fd is not a valid file descriptor and MAP_ANON was not set + if (fd < 0 && (flags & MAP_ANON) == 0) + { + return -EBADF; + } + + // check if a file mapping was requested, but fd is not open for reading + // file error checking is done in if statement below + file_t *file = NULL; + if (fd >= 0 && (flags & MAP_ANON) == 0) + { + // get the file and check if it is valid + file = fget(fd); + if (file == NULL) + { + return -EBADF; + } + + // ENODEV CHECKS + + // check if the file's vnode's mmap operation doesn't exist + if (file->f_vnode->vn_ops == NULL || file->f_vnode->vn_ops->mmap == NULL) + { + fput(&file); + return -ENODEV; + } + + // ACCESS CHECKS + + // check if thef FMODE_READ flag is not set + if ((file->f_mode & FMODE_READ) == 0) + { + fput(&file); + return -EACCES; + } + + // check if append mode is set and PROT_WRITE is set + if ((prot & PROT_WRITE) && (file->f_mode & FMODE_APPEND)) + { + fput(&file); + return -EACCES; + } + + // check if MAP_SHARED was requested and PROT_WRITE is set, but fd is not open in read/write (O_RDWR) mode + if ((flags & MAP_SHARED) && (prot & PROT_WRITE) && (file->f_mode & FMODE_READ) == 0) + { + fput(&file); + return -EACCES; + } + + // check if PROT_WRITE is set, but the file has FMODE_APPEND specified + if ((prot & PROT_WRITE) && (file->f_mode & FMODE_APPEND)) + { + fput(&file); + return -EACCES; + } + + fput(&file); + } + + + // Now that error checking is done, we can proceed with the mapping + vmarea_t *vma = NULL; + long err = vmmap_map( + curproc->p_vmmap, + file ? file->f_vnode : NULL, + ADDR_TO_PN(PAGE_ALIGN_DOWN(addr)), + ADDR_TO_PN(PAGE_ALIGN_UP((uintptr_t)addr + len)) - ADDR_TO_PN(PAGE_ALIGN_DOWN(addr)), + prot, + flags, + off, + VMMAP_DIR_HILO, + &vma + ); + + // check if vmmap_map() failed + if (err < 0) + { + return err; + } + + // set ret if it was provided + void *start = PN_TO_ADDR(vma->vma_start); + if (ret) + { + *ret = start; + } + + // flush the TLB + tlb_flush_range( + (uintptr_t) start, + PAGE_SIZE * (vma->vma_end - vma->vma_start) + ); + + // return 0 on success + return 0; } /* @@ -78,6 +204,37 @@ long do_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off, */ long do_munmap(void *addr, size_t len) { - NOT_YET_IMPLEMENTED("VM: do_munmap"); - return -1; + // NOT_YET_IMPLEMENTED("VM: do_munmap"); + + // Check if addr is page aligned + if (PAGE_ALIGNED(addr) == 0) + { + return -EINVAL; + } + + // Check if len is in bounds + if (len > USER_MEM_HIGH) + { + return -EINVAL; + } + + // Check if the addr is out of range of the user address space + if ((uintptr_t)addr < USER_MEM_LOW || (uintptr_t)addr + len > USER_MEM_HIGH) + { + return -EINVAL; + } + + // Check if len is 0 + if (len == 0) + { + return -EINVAL; + } + + // Remove the mapping + long ret = vmmap_remove( + curproc->p_vmmap, + ADDR_TO_PN(addr), + ADDR_TO_PN(PAGE_ALIGN_UP((uintptr_t)addr + len)) + ); + return ret; }
\ No newline at end of file |