aboutsummaryrefslogtreecommitdiff
path: root/kernel/vm/mmap.c
diff options
context:
space:
mode:
authorsotech117 <michael_foiani@brown.edu>2024-05-13 09:27:24 +0000
committersotech117 <michael_foiani@brown.edu>2024-05-13 09:27:24 +0000
commitf09878f6327426631d9419d825a4e8396e3b9dc4 (patch)
tree009d1f1b1386baf6d07b3b7d9a436590ada14094 /kernel/vm/mmap.c
parent0e2acbe54e5800621692c2f6e9e9590aa369e165 (diff)
weenix
Diffstat (limited to 'kernel/vm/mmap.c')
-rw-r--r--kernel/vm/mmap.c165
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