diff --git a/pintos/threads/mmu.c b/pintos/threads/mmu.c index a2c71cf..c365ab7 100644 --- a/pintos/threads/mmu.c +++ b/pintos/threads/mmu.c @@ -1,58 +1,58 @@ +#include "threads/mmu.h" + #include #include #include + +#include "intrinsic.h" #include "threads/init.h" -#include "threads/pte.h" #include "threads/palloc.h" +#include "threads/pte.h" #include "threads/thread.h" -#include "threads/mmu.h" -#include "intrinsic.h" -static uint64_t * -pgdir_walk (uint64_t *pdp, const uint64_t va, int create) { - int idx = PDX (va); - if (pdp) { - uint64_t *pte = (uint64_t *) pdp[idx]; - if (!((uint64_t) pte & PTE_P)) { - if (create) { - uint64_t *new_page = palloc_get_page (PAL_ZERO); - if (new_page) - pdp[idx] = vtop (new_page) | PTE_U | PTE_W | PTE_P; - else - return NULL; - } else - return NULL; - } - return (uint64_t *) ptov (PTE_ADDR (pdp[idx]) + 8 * PTX (va)); - } - return NULL; +static uint64_t* pgdir_walk(uint64_t* pdp, const uint64_t va, int create) { + int idx = PDX(va); + if (pdp) { + uint64_t* pte = (uint64_t*)pdp[idx]; + if (!((uint64_t)pte & PTE_P)) { + if (create) { + uint64_t* new_page = palloc_get_page(PAL_ZERO); + if (new_page) + pdp[idx] = vtop(new_page) | PTE_U | PTE_W | PTE_P; + else + return NULL; + } else + return NULL; + } + return (uint64_t*)ptov(PTE_ADDR(pdp[idx]) + 8 * PTX(va)); + } + return NULL; } -static uint64_t * -pdpe_walk (uint64_t *pdpe, const uint64_t va, int create) { - uint64_t *pte = NULL; - int idx = PDPE (va); - int allocated = 0; - if (pdpe) { - uint64_t *pde = (uint64_t *) pdpe[idx]; - if (!((uint64_t) pde & PTE_P)) { - if (create) { - uint64_t *new_page = palloc_get_page (PAL_ZERO); - if (new_page) { - pdpe[idx] = vtop (new_page) | PTE_U | PTE_W | PTE_P; - allocated = 1; - } else - return NULL; - } else - return NULL; - } - pte = pgdir_walk (ptov (PTE_ADDR (pdpe[idx])), va, create); - } - if (pte == NULL && allocated) { - palloc_free_page ((void *) ptov (PTE_ADDR (pdpe[idx]))); - pdpe[idx] = 0; - } - return pte; +static uint64_t* pdpe_walk(uint64_t* pdpe, const uint64_t va, int create) { + uint64_t* pte = NULL; + int idx = PDPE(va); + int allocated = 0; + if (pdpe) { + uint64_t* pde = (uint64_t*)pdpe[idx]; + if (!((uint64_t)pde & PTE_P)) { + if (create) { + uint64_t* new_page = palloc_get_page(PAL_ZERO); + if (new_page) { + pdpe[idx] = vtop(new_page) | PTE_U | PTE_W | PTE_P; + allocated = 1; + } else + return NULL; + } else + return NULL; + } + pte = pgdir_walk(ptov(PTE_ADDR(pdpe[idx])), va, create); + } + if (pte == NULL && allocated) { + palloc_free_page((void*)ptov(PTE_ADDR(pdpe[idx]))); + pdpe[idx] = 0; + } + return pte; } /* Returns the address of the page table entry for virtual @@ -61,164 +61,146 @@ pdpe_walk (uint64_t *pdpe, const uint64_t va, int create) { * on CREATE. If CREATE is true, then a new page table is * created and a pointer into it is returned. Otherwise, a null * pointer is returned. */ -uint64_t * -pml4e_walk (uint64_t *pml4e, const uint64_t va, int create) { - uint64_t *pte = NULL; - int idx = PML4 (va); - int allocated = 0; - if (pml4e) { - uint64_t *pdpe = (uint64_t *) pml4e[idx]; - if (!((uint64_t) pdpe & PTE_P)) { - if (create) { - uint64_t *new_page = palloc_get_page (PAL_ZERO); - if (new_page) { - pml4e[idx] = vtop (new_page) | PTE_U | PTE_W | PTE_P; - allocated = 1; - } else - return NULL; - } else - return NULL; - } - pte = pdpe_walk (ptov (PTE_ADDR (pml4e[idx])), va, create); - } - if (pte == NULL && allocated) { - palloc_free_page ((void *) ptov (PTE_ADDR (pml4e[idx]))); - pml4e[idx] = 0; - } - return pte; +uint64_t* pml4e_walk(uint64_t* pml4e, const uint64_t va, int create) { + uint64_t* pte = NULL; + int idx = PML4(va); + int allocated = 0; + if (pml4e) { + uint64_t* pdpe = (uint64_t*)pml4e[idx]; + if (!((uint64_t)pdpe & PTE_P)) { + if (create) { + uint64_t* new_page = palloc_get_page(PAL_ZERO); + if (new_page) { + pml4e[idx] = vtop(new_page) | PTE_U | PTE_W | PTE_P; + allocated = 1; + } else + return NULL; + } else + return NULL; + } + pte = pdpe_walk(ptov(PTE_ADDR(pml4e[idx])), va, create); + } + if (pte == NULL && allocated) { + palloc_free_page((void*)ptov(PTE_ADDR(pml4e[idx]))); + pml4e[idx] = 0; + } + return pte; } /* Creates a new page map level 4 (pml4) has mappings for kernel * virtual addresses, but none for user virtual addresses. * Returns the new page directory, or a null pointer if memory * allocation fails. */ -uint64_t * -pml4_create (void) { - uint64_t *pml4 = palloc_get_page (0); - if (pml4) - memcpy (pml4, base_pml4, PGSIZE); - return pml4; +uint64_t* pml4_create(void) { + uint64_t* pml4 = palloc_get_page(0); + if (pml4) + memcpy(pml4, base_pml4, PGSIZE); + return pml4; } -static bool -pt_for_each (uint64_t *pt, pte_for_each_func *func, void *aux, - unsigned pml4_index, unsigned pdp_index, unsigned pdx_index) { - for (unsigned i = 0; i < PGSIZE / sizeof(uint64_t *); i++) { - uint64_t *pte = &pt[i]; - if (((uint64_t) *pte) & PTE_P) { - void *va = (void *) (((uint64_t) pml4_index << PML4SHIFT) | - ((uint64_t) pdp_index << PDPESHIFT) | - ((uint64_t) pdx_index << PDXSHIFT) | - ((uint64_t) i << PTXSHIFT)); - if (!func (pte, va, aux)) - return false; - } - } - return true; +static bool pt_for_each(uint64_t* pt, pte_for_each_func* func, void* aux, unsigned pml4_index, + unsigned pdp_index, unsigned pdx_index) { + for (unsigned i = 0; i < PGSIZE / sizeof(uint64_t*); i++) { + uint64_t* pte = &pt[i]; + if (((uint64_t)*pte) & PTE_P) { + void* va = + (void*)(((uint64_t)pml4_index << PML4SHIFT) | ((uint64_t)pdp_index << PDPESHIFT) | + ((uint64_t)pdx_index << PDXSHIFT) | ((uint64_t)i << PTXSHIFT)); + if (!func(pte, va, aux)) + return false; + } + } + return true; } -static bool -pgdir_for_each (uint64_t *pdp, pte_for_each_func *func, void *aux, - unsigned pml4_index, unsigned pdp_index) { - for (unsigned i = 0; i < PGSIZE / sizeof(uint64_t *); i++) { - uint64_t *pte = ptov((uint64_t *) pdp[i]); - if (((uint64_t) pte) & PTE_P) - if (!pt_for_each ((uint64_t *) PTE_ADDR (pte), func, aux, - pml4_index, pdp_index, i)) - return false; - } - return true; +static bool pgdir_for_each(uint64_t* pdp, pte_for_each_func* func, void* aux, unsigned pml4_index, + unsigned pdp_index) { + for (unsigned i = 0; i < PGSIZE / sizeof(uint64_t*); i++) { + uint64_t* pte = ptov((uint64_t*)pdp[i]); + if (((uint64_t)pte) & PTE_P) + if (!pt_for_each((uint64_t*)PTE_ADDR(pte), func, aux, pml4_index, pdp_index, i)) + return false; + } + return true; } -static bool -pdp_for_each (uint64_t *pdp, - pte_for_each_func *func, void *aux, unsigned pml4_index) { - for (unsigned i = 0; i < PGSIZE / sizeof(uint64_t *); i++) { - uint64_t *pde = ptov((uint64_t *) pdp[i]); - if (((uint64_t) pde) & PTE_P) - if (!pgdir_for_each ((uint64_t *) PTE_ADDR (pde), func, - aux, pml4_index, i)) - return false; - } - return true; +static bool pdp_for_each(uint64_t* pdp, pte_for_each_func* func, void* aux, unsigned pml4_index) { + for (unsigned i = 0; i < PGSIZE / sizeof(uint64_t*); i++) { + uint64_t* pde = ptov((uint64_t*)pdp[i]); + if (((uint64_t)pde) & PTE_P) + if (!pgdir_for_each((uint64_t*)PTE_ADDR(pde), func, aux, pml4_index, i)) + return false; + } + return true; } /* Apply FUNC to each available pte entries including kernel's. */ -bool -pml4_for_each (uint64_t *pml4, pte_for_each_func *func, void *aux) { - for (unsigned i = 0; i < PGSIZE / sizeof(uint64_t *); i++) { - uint64_t *pdpe = ptov((uint64_t *) pml4[i]); - if (((uint64_t) pdpe) & PTE_P) - if (!pdp_for_each ((uint64_t *) PTE_ADDR (pdpe), func, aux, i)) - return false; - } - return true; +bool pml4_for_each(uint64_t* pml4, pte_for_each_func* func, void* aux) { + for (unsigned i = 0; i < PGSIZE / sizeof(uint64_t*); i++) { + uint64_t* pdpe = ptov((uint64_t*)pml4[i]); + if (((uint64_t)pdpe) & PTE_P) + if (!pdp_for_each((uint64_t*)PTE_ADDR(pdpe), func, aux, i)) + return false; + } + return true; } -static void -pt_destroy (uint64_t *pt) { - for (unsigned i = 0; i < PGSIZE / sizeof(uint64_t *); i++) { - uint64_t *pte = ptov((uint64_t *) pt[i]); - if (((uint64_t) pte) & PTE_P) - palloc_free_page ((void *) PTE_ADDR (pte)); - } - palloc_free_page ((void *) pt); +static void pt_destroy(uint64_t* pt) { + for (unsigned i = 0; i < PGSIZE / sizeof(uint64_t*); i++) { + uint64_t* pte = ptov((uint64_t*)pt[i]); + if (((uint64_t)pte) & PTE_P) + palloc_free_page((void*)PTE_ADDR(pte)); + } + palloc_free_page((void*)pt); } -static void -pgdir_destroy (uint64_t *pdp) { - for (unsigned i = 0; i < PGSIZE / sizeof(uint64_t *); i++) { - uint64_t *pte = ptov((uint64_t *) pdp[i]); - if (((uint64_t) pte) & PTE_P) - pt_destroy (PTE_ADDR (pte)); - } - palloc_free_page ((void *) pdp); +static void pgdir_destroy(uint64_t* pdp) { + for (unsigned i = 0; i < PGSIZE / sizeof(uint64_t*); i++) { + uint64_t* pte = ptov((uint64_t*)pdp[i]); + if (((uint64_t)pte) & PTE_P) + pt_destroy(PTE_ADDR(pte)); + } + palloc_free_page((void*)pdp); } -static void -pdpe_destroy (uint64_t *pdpe) { - for (unsigned i = 0; i < PGSIZE / sizeof(uint64_t *); i++) { - uint64_t *pde = ptov((uint64_t *) pdpe[i]); - if (((uint64_t) pde) & PTE_P) - pgdir_destroy ((void *) PTE_ADDR (pde)); - } - palloc_free_page ((void *) pdpe); +static void pdpe_destroy(uint64_t* pdpe) { + for (unsigned i = 0; i < PGSIZE / sizeof(uint64_t*); i++) { + uint64_t* pde = ptov((uint64_t*)pdpe[i]); + if (((uint64_t)pde) & PTE_P) + pgdir_destroy((void*)PTE_ADDR(pde)); + } + palloc_free_page((void*)pdpe); } /* Destroys pml4e, freeing all the pages it references. */ -void -pml4_destroy (uint64_t *pml4) { - if (pml4 == NULL) - return; - ASSERT (pml4 != base_pml4); - - /* if PML4 (vaddr) >= 1, it's kernel space by define. */ - uint64_t *pdpe = ptov ((uint64_t *) pml4[0]); - if (((uint64_t) pdpe) & PTE_P) - pdpe_destroy ((void *) PTE_ADDR (pdpe)); - palloc_free_page ((void *) pml4); +void pml4_destroy(uint64_t* pml4) { + if (pml4 == NULL) + return; + ASSERT(pml4 != base_pml4); + + /* if PML4 (vaddr) >= 1, it's kernel space by define. */ + uint64_t* pdpe = ptov((uint64_t*)pml4[0]); + if (((uint64_t)pdpe) & PTE_P) + pdpe_destroy((void*)PTE_ADDR(pdpe)); + palloc_free_page((void*)pml4); } /* Loads page directory PD into the CPU's page directory base * register. */ -void -pml4_activate (uint64_t *pml4) { - lcr3 (vtop (pml4 ? pml4 : base_pml4)); -} +void pml4_activate(uint64_t* pml4) { lcr3(vtop(pml4 ? pml4 : base_pml4)); } /* Looks up the physical address that corresponds to user virtual * address UADDR in pml4. Returns the kernel virtual address * corresponding to that physical address, or a null pointer if * UADDR is unmapped. */ -void * -pml4_get_page (uint64_t *pml4, const void *uaddr) { - ASSERT (is_user_vaddr (uaddr)); +void* pml4_get_page(uint64_t* pml4, const void* uaddr) { + ASSERT(is_user_vaddr(uaddr)); - uint64_t *pte = pml4e_walk (pml4, (uint64_t) uaddr, 0); + uint64_t* pte = pml4e_walk(pml4, (uint64_t)uaddr, 0); - if (pte && (*pte & PTE_P)) - return ptov (PTE_ADDR (*pte)) + pg_ofs (uaddr); - return NULL; + if (pte && (*pte & PTE_P)) + return ptov(PTE_ADDR(*pte)) + pg_ofs(uaddr); + return NULL; } /* Adds a mapping in page map level 4 PML4 from user virtual page @@ -229,87 +211,86 @@ pml4_get_page (uint64_t *pml4, const void *uaddr) { * otherwise it is read-only. * Returns true if successful, false if memory allocation * failed. */ -bool -pml4_set_page (uint64_t *pml4, void *upage, void *kpage, bool rw) { - ASSERT (pg_ofs (upage) == 0); - ASSERT (pg_ofs (kpage) == 0); - ASSERT (is_user_vaddr (upage)); - ASSERT (pml4 != base_pml4); - - uint64_t *pte = pml4e_walk (pml4, (uint64_t) upage, 1); - - if (pte) - *pte = vtop (kpage) | PTE_P | (rw ? PTE_W : 0) | PTE_U; - return pte != NULL; +bool pml4_set_page(uint64_t* pml4, void* upage, void* kpage, bool rw) { + ASSERT(pg_ofs(upage) == 0); + ASSERT(pg_ofs(kpage) == 0); + ASSERT(is_user_vaddr(upage)); + ASSERT(pml4 != base_pml4); + + uint64_t* pte = pml4e_walk(pml4, (uint64_t)upage, 1); + + if (pte) + *pte = vtop(kpage) | PTE_P | (rw ? PTE_W : 0) | PTE_U; + return pte != NULL; } /* Marks user virtual page UPAGE "not present" in page * directory PD. Later accesses to the page will fault. Other * bits in the page table entry are preserved. * UPAGE need not be mapped. */ -void -pml4_clear_page (uint64_t *pml4, void *upage) { - uint64_t *pte; - ASSERT (pg_ofs (upage) == 0); - ASSERT (is_user_vaddr (upage)); - - pte = pml4e_walk (pml4, (uint64_t) upage, false); - - if (pte != NULL && (*pte & PTE_P) != 0) { - *pte &= ~PTE_P; - if (rcr3 () == vtop (pml4)) - invlpg ((uint64_t) upage); - } +void pml4_clear_page(uint64_t* pml4, void* upage) { + uint64_t* pte; + ASSERT(pg_ofs(upage) == 0); + ASSERT(is_user_vaddr(upage)); + + pte = pml4e_walk(pml4, (uint64_t)upage, false); + + if (pte != NULL && (*pte & PTE_P) != 0) { + *pte &= ~PTE_P; + if (rcr3() == vtop(pml4)) + invlpg((uint64_t)upage); + } } /* Returns true if the PTE for virtual page VPAGE in PML4 is dirty, * that is, if the page has been modified since the PTE was * installed. * Returns false if PML4 contains no PTE for VPAGE. */ -bool -pml4_is_dirty (uint64_t *pml4, const void *vpage) { - uint64_t *pte = pml4e_walk (pml4, (uint64_t) vpage, false); - return pte != NULL && (*pte & PTE_D) != 0; +bool pml4_is_dirty(uint64_t* pml4, const void* vpage) { + uint64_t* pte = pml4e_walk(pml4, (uint64_t)vpage, false); + return pte != NULL && (*pte & PTE_D) != 0; +} + +bool pml4_is_writable(uint64_t* pml4, const void* vpage) { + uint64_t* pte = pml4e_walk(pml4, (uint64_t)vpage, false); + return pte != NULL && (*pte & PTE_W) != 0; } /* Set the dirty bit to DIRTY in the PTE for virtual page VPAGE * in PML4. */ -void -pml4_set_dirty (uint64_t *pml4, const void *vpage, bool dirty) { - uint64_t *pte = pml4e_walk (pml4, (uint64_t) vpage, false); - if (pte) { - if (dirty) - *pte |= PTE_D; - else - *pte &= ~(uint32_t) PTE_D; - - if (rcr3 () == vtop (pml4)) - invlpg ((uint64_t) vpage); - } +void pml4_set_dirty(uint64_t* pml4, const void* vpage, bool dirty) { + uint64_t* pte = pml4e_walk(pml4, (uint64_t)vpage, false); + if (pte) { + if (dirty) + *pte |= PTE_D; + else + *pte &= ~(uint32_t)PTE_D; + + if (rcr3() == vtop(pml4)) + invlpg((uint64_t)vpage); + } } /* Returns true if the PTE for virtual page VPAGE in PML4 has been * accessed recently, that is, between the time the PTE was * installed and the last time it was cleared. Returns false if * PML4 contains no PTE for VPAGE. */ -bool -pml4_is_accessed (uint64_t *pml4, const void *vpage) { - uint64_t *pte = pml4e_walk (pml4, (uint64_t) vpage, false); - return pte != NULL && (*pte & PTE_A) != 0; +bool pml4_is_accessed(uint64_t* pml4, const void* vpage) { + uint64_t* pte = pml4e_walk(pml4, (uint64_t)vpage, false); + return pte != NULL && (*pte & PTE_A) != 0; } /* Sets the accessed bit to ACCESSED in the PTE for virtual page VPAGE in PD. */ -void -pml4_set_accessed (uint64_t *pml4, const void *vpage, bool accessed) { - uint64_t *pte = pml4e_walk (pml4, (uint64_t) vpage, false); - if (pte) { - if (accessed) - *pte |= PTE_A; - else - *pte &= ~(uint32_t) PTE_A; - - if (rcr3 () == vtop (pml4)) - invlpg ((uint64_t) vpage); - } +void pml4_set_accessed(uint64_t* pml4, const void* vpage, bool accessed) { + uint64_t* pte = pml4e_walk(pml4, (uint64_t)vpage, false); + if (pte) { + if (accessed) + *pte |= PTE_A; + else + *pte &= ~(uint32_t)PTE_A; + + if (rcr3() == vtop(pml4)) + invlpg((uint64_t)vpage); + } } diff --git a/pintos/userprog/syscall.c b/pintos/userprog/syscall.c index e702429..67e9793 100644 --- a/pintos/userprog/syscall.c +++ b/pintos/userprog/syscall.c @@ -17,6 +17,7 @@ #include "userprog/gdt.h" #include "userprog/process.h" #include "userprog/validate.h" +#include "vm/file.h" void syscall_entry(void); void syscall_handler(struct intr_frame*); @@ -51,6 +52,7 @@ static void syscall_seek(int fd, unsigned position); static unsigned syscall_tell(int fd); static void syscall_close(int fd); static int syscall_dup2(int oldfd, int newfd); +static uint64_t syscall_mmap(void* addr, size_t length, int writable, int fd, off_t offset); void syscall_init(void) { write_msr(MSR_STAR, ((uint64_t)SEL_UCSEG - 0x10) << 48 | ((uint64_t)SEL_KCSEG) << 32); @@ -65,7 +67,9 @@ void syscall_init(void) { /* The main system call interface */ void syscall_handler(struct intr_frame* f) { - uint64_t arg1 = f->R.rdi, arg2 = f->R.rsi, arg3 = f->R.rdx; + thread_current()->tf = *f; + + uint64_t arg1 = f->R.rdi, arg2 = f->R.rsi, arg3 = f->R.rdx, arg4 = f->R.r10, arg5 = f->R.r8; switch (f->R.rax) { case SYS_HALT: syscall_halt(); @@ -112,6 +116,9 @@ void syscall_handler(struct intr_frame* f) { case SYS_DUP2: f->R.rax = syscall_dup2(arg1, arg2); break; + case SYS_MMAP: + f->R.rax = syscall_mmap(arg1, arg2, arg3, arg4, arg5); + break; } } @@ -123,15 +130,18 @@ static void syscall_exit(int status) { } static pid_t syscall_fork(const char* thread_name, struct intr_frame* if_) { - if (thread_name == NULL || !valid_address(thread_name, false)) syscall_exit(-1); + if (thread_name == NULL || !valid_address(thread_name, false)) + syscall_exit(-1); return process_fork(thread_name, if_); } static int syscall_exec(const char* cmd_line) { - if (cmd_line == NULL || !valid_address(cmd_line, false)) syscall_exit(-1); + if (cmd_line == NULL || !valid_address(cmd_line, false)) + syscall_exit(-1); char* cmd_line_copy = palloc_get_page(0); - if (cmd_line_copy == NULL) syscall_exit(-1); + if (cmd_line_copy == NULL) + syscall_exit(-1); strlcpy(cmd_line_copy, cmd_line, PGSIZE); process_exec(cmd_line_copy); @@ -143,7 +153,8 @@ static int syscall_wait(int pid) { return process_wait(pid); } static bool syscall_create(const char* file, unsigned initial_size) { bool success; - if (!valid_address(file, false)) syscall_exit(-1); + if (!valid_address(file, false)) + syscall_exit(-1); lock_acquire(&file_lock); success = filesys_create(file, initial_size); lock_release(&file_lock); @@ -153,7 +164,8 @@ static bool syscall_create(const char* file, unsigned initial_size) { static bool syscall_remove(const char* file) { bool success; - if (!valid_address(file, false)) syscall_exit(-1); + if (!valid_address(file, false)) + syscall_exit(-1); lock_acquire(&file_lock); success = filesys_remove(file); lock_release(&file_lock); @@ -162,11 +174,13 @@ static bool syscall_remove(const char* file) { static int syscall_open(const char* file) { struct file* new_entry; - if (!valid_address(file, false)) syscall_exit(-1); + if (!valid_address(file, false)) + syscall_exit(-1); lock_acquire(&file_lock); new_entry = filesys_open(file); lock_release(&file_lock); - if (!new_entry) return -1; + if (!new_entry) + return -1; return fd_allocate(thread_current(), new_entry); } @@ -175,7 +189,8 @@ static int syscall_filesize(int fd) { int result; entry = get_fd_entry(thread_current(), fd); - if (!entry || entry == stdin_entry || entry == stdout_entry) return -1; + if (!entry || entry == stdin_entry || entry == stdout_entry) + return -1; lock_acquire(&file_lock); result = file_length(entry); @@ -186,11 +201,14 @@ static int syscall_filesize(int fd) { static int syscall_read(int fd, void* buffer, unsigned size) { struct file* entry; int result; - if (size == 0) return 0; + if (size == 0) + return 0; - if (!valid_address(buffer, true) || !valid_address(buffer + size - 1, true)) syscall_exit(-1); + if (!valid_address(buffer, true) || !valid_address(buffer + size - 1, true)) + syscall_exit(-1); entry = get_fd_entry(thread_current(), fd); - if (!entry || entry == stdout_entry) return -1; + if (!entry || entry == stdout_entry) + return -1; lock_acquire(&file_lock); if (entry == stdin_entry) { @@ -207,9 +225,11 @@ static int syscall_write(int fd, const void* buffer, unsigned size) { struct file* entry; int result; - if (!valid_address(buffer, false) || !valid_address(buffer + size - 1, false)) syscall_exit(-1); + if (!valid_address(buffer, false) || !valid_address(buffer + size - 1, false)) + syscall_exit(-1); entry = get_fd_entry(thread_current(), fd); - if (!entry || entry == stdin_entry) return -1; + if (!entry || entry == stdin_entry) + return -1; lock_acquire(&file_lock); if (entry == stdout_entry) { @@ -226,7 +246,8 @@ static void syscall_seek(int fd, unsigned position) { struct file* entry; entry = get_fd_entry(thread_current(), fd); - if (!entry) return; + if (!entry) + return; lock_acquire(&file_lock); file_seek(entry, position); lock_release(&file_lock); @@ -237,7 +258,8 @@ static unsigned syscall_tell(int fd) { unsigned result; entry = get_fd_entry(thread_current(), fd); - if (!entry) return 0; + if (!entry) + return 0; lock_acquire(&file_lock); result = file_tell(entry); @@ -252,11 +274,27 @@ static void syscall_close(int fd) { } static int syscall_dup2(int oldfd, int newfd) { - if (oldfd < 0 || newfd < 0) return -1; - if (oldfd == newfd) return newfd; + if (oldfd < 0 || newfd < 0) + return -1; + if (oldfd == newfd) + return newfd; lock_acquire(&file_lock); int result = fd_dup2(thread_current(), oldfd, newfd); lock_release(&file_lock); return result; +} + +static uint64_t syscall_mmap(void* addr, size_t length, int writable, int fd, off_t offset) { + struct file* file; + struct thread* cur; + + if (fd == 0 || fd == 1) + return 0; + + cur = thread_current(); + file = get_fd_entry(cur, fd); + if (file == NULL) + return 0; + return do_mmap(addr, length, writable, file, offset); } \ No newline at end of file diff --git a/pintos/userprog/validate.c b/pintos/userprog/validate.c index 6a84bd1..efc7cd1 100644 --- a/pintos/userprog/validate.c +++ b/pintos/userprog/validate.c @@ -1,5 +1,6 @@ #include "userprog/validate.h" +#include "threads/mmu.h" #include "threads/thread.h" #include "threads/vaddr.h" @@ -7,8 +8,24 @@ static int64_t get_user(const uint8_t* uaddr); static int64_t put_user(uint8_t* udst, uint8_t byte); bool valid_address(const void* uaddr, bool write) { - if (uaddr == NULL || !is_user_vaddr(uaddr)) return false; - return (write ? put_user(uaddr, 0) : get_user(uaddr)) != -1; + struct thread* t = thread_current(); + void* page_addr; + + // 유효한 주소가 아니거나 || 커널 영역의 주소라면, false + if (uaddr == NULL || !is_user_vaddr(uaddr)) + return false; + + // 메모리가 매핑되어 있는지 확인 + if (get_user(uaddr) == -1) + return false; + + // 쓰기 권한 필요 없으면 통과 + if (!write) + return true; + + // pml4 테이블로 해당 page의 쓰기 권한 확인 + page_addr = pg_round_down(uaddr); + return pml4_is_writable(t->pml4, page_addr); } static int64_t get_user(const uint8_t* uaddr) { diff --git a/pintos/vm/vm.c b/pintos/vm/vm.c index e44e4c7..0d6f4fc 100644 --- a/pintos/vm/vm.c +++ b/pintos/vm/vm.c @@ -1,161 +1,158 @@ /* vm.c: Generic interface for virtual memory objects. */ +#include "vm/vm.h" + #include + +#include "filesys/file.h" #include "threads/malloc.h" -#include "threads/vaddr.h" #include "threads/mmu.h" #include "threads/thread.h" +#include "threads/vaddr.h" #include "userprog/process.h" -#include "vm/vm.h" #include "vm/inspect.h" -#include "filesys/file.h" /* Initializes the virtual memory subsystem by invoking each subsystem's * intialize codes. */ -void -vm_init (void) { - vm_anon_init (); - vm_file_init (); -#ifdef EFILESYS /* For project 4 */ - pagecache_init (); +void vm_init(void) { + vm_anon_init(); + vm_file_init(); +#ifdef EFILESYS /* For project 4 */ + pagecache_init(); #endif - register_inspect_intr (); - /* DO NOT MODIFY UPPER LINES. */ - /* TODO: Your code goes here. */ + register_inspect_intr(); + /* DO NOT MODIFY UPPER LINES. */ + /* TODO: Your code goes here. */ } /* Get the type of the page. This function is useful if you want to know the * type of the page after it will be initialized. * This function is fully implemented now. */ -enum vm_type -page_get_type (struct page *page) { - int ty = VM_TYPE (page->operations->type); - switch (ty) { - case VM_UNINIT: - return VM_TYPE (page->uninit.type); - default: - return ty; - } +enum vm_type page_get_type(struct page* page) { + int ty = VM_TYPE(page->operations->type); + switch (ty) { + case VM_UNINIT: + return VM_TYPE(page->uninit.type); + default: + return ty; + } } /* Helpers */ -static struct frame *vm_get_victim (void); -static bool vm_do_claim_page (struct page *page); -static struct frame *vm_evict_frame (void); -static uint64_t page_hash (const struct hash_elem *e, void *aux); -static bool page_less (const struct hash_elem *a, const struct hash_elem *b, void *aux); -static bool should_grow_stack (struct intr_frame *f, void *addr, bool user); -static void spt_destroy_page (struct hash_elem *elem, void *aux); +static struct frame* vm_get_victim(void); +static bool vm_do_claim_page(struct page* page); +static struct frame* vm_evict_frame(void); +static uint64_t page_hash(const struct hash_elem* e, void* aux); +static bool page_less(const struct hash_elem* a, const struct hash_elem* b, void* aux); +static bool should_grow_stack(struct intr_frame* f, void* addr, bool user); +static void spt_destroy_page(struct hash_elem* elem, void* aux); #define STACK_LIMIT (1 << 20) #define STACK_HEURISTIC 8 -bool vm_alloc_page_with_initializer (enum vm_type type, void *upage, bool writable, - vm_initializer *init, void *aux) { - - ASSERT (VM_TYPE(type) != VM_UNINIT) - - struct supplemental_page_table *spt = &thread_current ()->spt; - - if (spt_find_page (spt, upage) == NULL) { - struct page *page = malloc (sizeof *page); - bool (*initializer) (struct page *, enum vm_type, void *) = NULL; - - if (page == NULL) - goto err; - - switch (VM_TYPE (type)) { - case VM_ANON: - initializer = anon_initializer; - break; - case VM_FILE: - initializer = file_backed_initializer; - break; - default: - free (page); - goto err; - } - - uninit_new (page, upage, init, type, aux, initializer); - page->writable = writable; - - if (!spt_insert_page (spt, page)) { - free (page); - goto err; - } - return true; - } +bool vm_alloc_page_with_initializer(enum vm_type type, void* upage, bool writable, + vm_initializer* init, void* aux) { + ASSERT(VM_TYPE(type) != VM_UNINIT) + + struct supplemental_page_table* spt = &thread_current()->spt; + + if (spt_find_page(spt, upage) == NULL) { + struct page* page = malloc(sizeof *page); + bool (*initializer)(struct page*, enum vm_type, void*) = NULL; + + if (page == NULL) + goto err; + + switch (VM_TYPE(type)) { + case VM_ANON: + initializer = anon_initializer; + break; + case VM_FILE: + initializer = file_backed_initializer; + break; + default: + free(page); + goto err; + } + + uninit_new(page, upage, init, type, aux, initializer); + page->writable = writable; + + if (!spt_insert_page(spt, page)) { + free(page); + goto err; + } + return true; + } err: - return false; + return false; } /* Find VA from spt and return page. On error, return NULL. */ -struct page *spt_find_page (struct supplemental_page_table *spt, void *va) { - /* TODO: Fill this function. */ - struct page dummy_page; - struct hash_elem *elem; +struct page* spt_find_page(struct supplemental_page_table* spt, void* va) { + /* TODO: Fill this function. */ + struct page dummy_page; + struct hash_elem* elem; - if (spt == NULL || va == NULL) - return NULL; + if (spt == NULL || va == NULL) + return NULL; - dummy_page.va = pg_round_down (va); - elem = hash_find (&spt->hash_table, &dummy_page.hash_elem); + dummy_page.va = pg_round_down(va); + elem = hash_find(&spt->hash_table, &dummy_page.hash_elem); - if (elem == NULL) - return NULL; - - return hash_entry(elem, struct page, hash_elem); + if (elem == NULL) + return NULL; + + return hash_entry(elem, struct page, hash_elem); } /* Insert PAGE into spt with validation. */ -bool spt_insert_page (struct supplemental_page_table *spt, struct page *page) { - if (spt == NULL || page == NULL || page->va == NULL) - return false; +bool spt_insert_page(struct supplemental_page_table* spt, struct page* page) { + if (spt == NULL || page == NULL || page->va == NULL) + return false; - // page->va = pg_round_down (page->va); - return hash_insert (&spt->hash_table, &page->hash_elem) == NULL; + // page->va = pg_round_down (page->va); + return hash_insert(&spt->hash_table, &page->hash_elem) == NULL; } -bool spt_remove_page (struct supplemental_page_table *spt, struct page *page) { - struct hash_elem *result; +bool spt_remove_page(struct supplemental_page_table* spt, struct page* page) { + struct hash_elem* result; - if (spt == NULL || page == NULL) - return false; + if (spt == NULL || page == NULL) + return false; - result = hash_delete(&spt->hash_table, &page->hash_elem); + result = hash_delete(&spt->hash_table, &page->hash_elem); - if (result != NULL) { - vm_dealloc_page (page); - return true; - } - return false; + if (result != NULL) { + vm_dealloc_page(page); + return true; + } + return false; } /* Get the struct frame, that will be evicted. */ -static struct frame * -vm_get_victim (void) { - struct frame *victim = NULL; - /* TODO: The policy for eviction is up to you. */ +static struct frame* vm_get_victim(void) { + struct frame* victim = NULL; + /* TODO: The policy for eviction is up to you. */ - return victim; + return victim; } /* Evict one page and return the corresponding frame. * Return NULL on error.*/ -static struct frame * -vm_evict_frame (void) { - struct frame *victim UNUSED = vm_get_victim (); - /* TODO: swap out the victim and return the evicted frame. */ +static struct frame* vm_evict_frame(void) { + struct frame* victim UNUSED = vm_get_victim(); + /* TODO: swap out the victim and return the evicted frame. */ - return NULL; + return NULL; } /* palloc() and get frame. If there is no available page, evict the page * and return it. This always return valid address. That is, if the user pool * memory is full, this function evicts the frame to get the available memory * space.*/ -static struct frame * vm_get_frame (void) { - struct frame *frame = NULL; - void *kva; +static struct frame* vm_get_frame(void) { + struct frame* frame = NULL; + void* kva; kva = palloc_get_page(PAL_USER); if (kva == NULL) { @@ -171,191 +168,194 @@ static struct frame * vm_get_frame (void) { frame->kva = kva; frame->page = NULL; - ASSERT (frame != NULL); - ASSERT (frame->page == NULL); + ASSERT(frame != NULL); + ASSERT(frame->page == NULL); return frame; } /* Growing the stack. */ -static void -vm_stack_growth (void *addr UNUSED) { -} +static void vm_stack_growth(void* addr) { + void* page_addr = pg_round_down(addr); -/* Handle the fault on write_protected page */ -static bool -vm_handle_wp (struct page *page UNUSED) { + if (vm_alloc_page(VM_ANON | VM_MARKER_0, page_addr, true)) + vm_claim_page(page_addr); } -bool vm_try_handle_fault (struct intr_frame *f, void *addr, bool user, bool write, bool not_present) { - struct supplemental_page_table *spt; - struct page *page; +/* Handle the fault on write_protected page */ +static bool vm_handle_wp(struct page* page UNUSED) { return false; } - spt = &thread_current()->spt; - page = NULL; +bool vm_try_handle_fault(struct intr_frame* f, void* addr, bool user, bool write, + bool not_present) { + struct supplemental_page_table* spt; + struct page* page; - if (is_kernel_vaddr (addr) || addr == NULL) - return false; + spt = &thread_current()->spt; + page = NULL; - if (!not_present) { - page = spt_find_page (spt, addr); + if (is_kernel_vaddr(addr) || addr == NULL) + return false; - if (page == NULL || !write) - return false; - } + page = spt_find_page(spt, addr); - page = spt_find_page (spt, addr); + if (page != NULL) { + if (write && !page->writable) + return vm_handle_wp(page); - if (page == NULL || write == 1 && !(page->writable)) - return false; + return vm_do_claim_page(page); + } + if (page == NULL) { + if (should_grow_stack(f, addr, user)) { + vm_stack_growth(addr); + return true; + } + return false; + } - return vm_do_claim_page (page); + return false; } - /* Free the page. * DO NOT MODIFY THIS FUNCTION. */ -void -vm_dealloc_page (struct page *page) { - destroy (page); - free (page); +void vm_dealloc_page(struct page* page) { + destroy(page); + free(page); } /* Claim the page that allocate on VA. */ -bool vm_claim_page (void *va) { - struct page *page = NULL; - - page = spt_find_page(&thread_current()->spt, va); - if (page == NULL) { - return false; - } - - return vm_do_claim_page (page); +bool vm_claim_page(void* va) { + struct page* page = NULL; + + page = spt_find_page(&thread_current()->spt, va); + if (page == NULL) + return false; + + return vm_do_claim_page(page); } /* Claim the PAGE and set up the mmu. */ -static bool vm_do_claim_page (struct page *page) { - struct frame *frame; - - if (page == NULL) - return false; - - frame = vm_get_frame (); +static bool vm_do_claim_page(struct page* page) { + struct frame* frame; + + if (page == NULL) + return false; + + frame = vm_get_frame(); frame->page = page; page->frame = frame; - if (!pml4_set_page(thread_current()->pml4, page->va, frame->kva, page->writable)) - return false; - - return swap_in (page, frame->kva); + if (!pml4_set_page(thread_current()->pml4, page->va, frame->kva, page->writable)) + return false; + + return swap_in(page, frame->kva); } /* Initialize new supplemental page table */ -void -supplemental_page_table_init (struct supplemental_page_table *spt UNUSED) { - hash_init(&spt->hash_table, page_hash, page_less, NULL); +void supplemental_page_table_init(struct supplemental_page_table* spt UNUSED) { + hash_init(&spt->hash_table, page_hash, page_less, NULL); } /* Copy supplemental page table from src to dst */ -bool supplemental_page_table_copy (struct supplemental_page_table *dst, struct supplemental_page_table *src) { - struct hash_iterator i; - - hash_first (&i, &src->hash_table); - while (hash_next (&i)) { - struct page *page = hash_entry (hash_cur (&i), struct page, hash_elem); - enum vm_type type = page->operations->type; - - switch (type) { - case VM_UNINIT: - void *aux = page->uninit.aux; - - if (aux != NULL) { - segment_lazy_load_info *src_aux = (segment_lazy_load_info *)aux; - segment_lazy_load_info *dst_aux = (segment_lazy_load_info *)malloc(sizeof(segment_lazy_load_info)); - if (dst_aux == NULL) { - return false; - } - - memcpy(dst_aux , src_aux, sizeof(segment_lazy_load_info)); - dst_aux->file = file_reopen(src_aux->file); - if(!vm_alloc_page_with_initializer(page->uninit.type, page->va, page->writable, page->uninit.init, dst_aux)) { - free(dst_aux); - return false; - } - - } else { - if (!vm_alloc_page_with_initializer(page->uninit.type, page->va, page->writable, page->uninit.init, page->uninit.aux)) - return false; - } - - - break; - - case VM_ANON: - if (!vm_alloc_page(VM_ANON, page->va, page->writable)) - return false; - - - if (!vm_claim_page(page->va)) - return false; - - memcpy(spt_find_page(dst, page->va)->frame->kva, page->frame->kva, PGSIZE); - - break; - - default: - break; - } - } +bool supplemental_page_table_copy(struct supplemental_page_table* dst, + struct supplemental_page_table* src) { + struct hash_iterator i; + + hash_first(&i, &src->hash_table); + while (hash_next(&i)) { + struct page* page = hash_entry(hash_cur(&i), struct page, hash_elem); + enum vm_type type = page->operations->type; + + switch (type) { + case VM_UNINIT: + void* aux = page->uninit.aux; + + if (aux != NULL) { + segment_lazy_load_info* src_aux = (segment_lazy_load_info*)aux; + segment_lazy_load_info* dst_aux = + (segment_lazy_load_info*)malloc(sizeof(segment_lazy_load_info)); + if (dst_aux == NULL) { + return false; + } + + memcpy(dst_aux, src_aux, sizeof(segment_lazy_load_info)); + dst_aux->file = file_reopen(src_aux->file); + if (!vm_alloc_page_with_initializer(page->uninit.type, page->va, page->writable, + page->uninit.init, dst_aux)) { + free(dst_aux); + return false; + } + + } else { + if (!vm_alloc_page_with_initializer(page->uninit.type, page->va, page->writable, + page->uninit.init, page->uninit.aux)) + return false; + } + + break; + + case VM_ANON: + if (!vm_alloc_page(VM_ANON, page->va, page->writable)) + return false; + + if (!vm_claim_page(page->va)) + return false; + + memcpy(spt_find_page(dst, page->va)->frame->kva, page->frame->kva, PGSIZE); + + break; + + default: + break; + } + } - return true; + return true; } -void supplemental_page_table_kill (struct supplemental_page_table *spt UNUSED) { - if (spt == NULL) - return; +void supplemental_page_table_kill(struct supplemental_page_table* spt UNUSED) { + if (spt == NULL) + return; - hash_destroy (&spt->hash_table, spt_destroy_page); + hash_destroy(&spt->hash_table, spt_destroy_page); } -static void spt_destroy_page (struct hash_elem *elem, void *aux UNUSED) { - struct page *page = hash_entry (elem, struct page, hash_elem); +static void spt_destroy_page(struct hash_elem* elem, void* aux UNUSED) { + struct page* page = hash_entry(elem, struct page, hash_elem); - if (page->frame != NULL) - vm_dealloc_page (page); + if (page->frame != NULL) + vm_dealloc_page(page); } -static uint64_t page_hash (const struct hash_elem *e, void *aux UNUSED) { - const struct page *page; - page = hash_entry (e, struct page, hash_elem); - return hash_bytes (&page->va, sizeof page->va); +static uint64_t page_hash(const struct hash_elem* e, void* aux UNUSED) { + const struct page* page; + page = hash_entry(e, struct page, hash_elem); + return hash_bytes(&page->va, sizeof page->va); } -static bool page_less (const struct hash_elem *a, const struct hash_elem *b, void *aux UNUSED) { - const struct page *page_a, *page_b; - page_a = hash_entry (a, struct page, hash_elem); - page_b = hash_entry (b, struct page, hash_elem); - return page_a->va < page_b->va; +static bool page_less(const struct hash_elem* a, const struct hash_elem* b, void* aux UNUSED) { + const struct page *page_a, *page_b; + page_a = hash_entry(a, struct page, hash_elem); + page_b = hash_entry(b, struct page, hash_elem); + return page_a->va < page_b->va; } -// static bool should_grow_stack (struct intr_frame *f, void *addr, bool user) { -// uint8_t *rsp = NULL; -// uint8_t *fault_addr = addr; +static bool should_grow_stack(struct intr_frame* f, void* addr, bool user) { + uint8_t* rsp = NULL; + uint8_t* fault_addr = addr; -// if (!is_user_vaddr (addr)) -// return false; + if (!is_user_vaddr(addr)) + return false; -// if (user && f != NULL) -// rsp = f->rsp; + if (user && f != NULL) + rsp = f->rsp; -// if (rsp == NULL) -// rsp = thread_current ()->tf.rsp; + if (rsp == NULL) + rsp = thread_current()->tf.rsp; -// if (fault_addr >= (uint8_t *) USER_STACK) -// return false; + if (fault_addr >= (uint8_t*)USER_STACK) + return false; -// if (fault_addr < (uint8_t *) USER_STACK - STACK_LIMIT) -// return false; - -// return rsp != NULL && fault_addr >= rsp - STACK_HEURISTIC; -// } + if (fault_addr < (uint8_t*)USER_STACK - STACK_LIMIT) + return false; + return rsp != NULL && fault_addr >= rsp - STACK_HEURISTIC; +}