diff --git a/src/userprog/syscall.c b/src/userprog/syscall.c index e85f194..7e94048 100644 --- a/src/userprog/syscall.c +++ b/src/userprog/syscall.c @@ -11,6 +11,7 @@ #include "threads/synch.h" #include "userprog/process.h" #include "userprog/pagedir.h" +#include "vm/page.h" #include "vm/mmap.h" #include #include @@ -404,7 +405,56 @@ syscall_close (int fd) static mapid_t syscall_mmap (int fd, void *addr) { - return MMAP_FAILURE; + /* Ensure the FD is for a file in the filesystem (not STDIN or STDOUT). */ + if (fd == STDOUT_FILENO || fd == STDIN_FILENO) + return MMAP_FAILURE; + + /* Validate that there is a file associated with the given FD. */ + struct open_file *file_info = fd_get_file (fd); + if (file_info == NULL) + return MMAP_FAILURE; + + /* Ensure that the address is page-aligned and it's neither NULL nor zero. */ + if (addr == 0 || addr == NULL || pg_ofs (addr) != 0) + return MMAP_FAILURE; + + /* Reopen the file to obtain a separate and independent reference to the file + for the mapping. */ + struct file *file = file_reopen (file_info->file); + if (file == NULL) + return MMAP_FAILURE; + + /* Get the size of the file. Mmap fails if the file is empty. */ + off_t file_size = file_length (file); + if (file_size == 0) + return MMAP_FAILURE; + + /* Check and ensure that there is enough space in the user virtual memory to + hold the entire file. */ + for (off_t ofs = 0; ofs < file_size; ofs += PGSIZE) + { + if (page_get (addr + ofs) != NULL) + return MMAP_FAILURE; + } + + /* Map the file data into the user virtual memory starting from addr. */ + for (off_t ofs = 0; ofs < file_size; ofs += PGSIZE) + { + off_t read_bytes = file_size - ofs < PGSIZE ? file_size - ofs : PGSIZE; + off_t zero_bytes = PGSIZE - read_bytes; + + if (page_insert (file, ofs, addr + ofs, read_bytes, zero_bytes, true, + PAGE_EXECUTABLE) == NULL) + return MMAP_FAILURE; + } + + /* Create a new mapping for the file. */ + struct mmap_entry *mmap = mmap_insert (file, addr); + if (mmap == NULL) + return MMAP_FAILURE; + + + return mmap->mapping; } /* Handles the syscall for unmapping a memory mapped file. */