diff --git a/pintos/include/userprog/process.h b/pintos/include/userprog/process.h index ece3420..3167ebd 100644 --- a/pintos/include/userprog/process.h +++ b/pintos/include/userprog/process.h @@ -9,6 +9,7 @@ int process_exec (void *f_name); int process_wait (tid_t); void process_exit (void); void process_activate (struct thread *next); +bool lazy_load_segment(struct page *page, void *aux); #endif /* userprog/process.h */ diff --git a/pintos/include/vm/file.h b/pintos/include/vm/file.h index cf1b8b4..56e4b17 100644 --- a/pintos/include/vm/file.h +++ b/pintos/include/vm/file.h @@ -3,10 +3,12 @@ #include "filesys/file.h" #include "vm/vm.h" + struct page; enum vm_type; struct file_page { + void *aux; }; void vm_file_init (void); diff --git a/pintos/include/vm/vm.h b/pintos/include/vm/vm.h index 3d0da9e..0d1e14f 100644 --- a/pintos/include/vm/vm.h +++ b/pintos/include/vm/vm.h @@ -51,6 +51,7 @@ struct page { /* Your implementation */ struct hash_elem hash_elem; bool writable; + unsigned page_length; /* Per-type data are binded into the union. * Each function automatically detects the current union */ diff --git a/pintos/userprog/exception.c b/pintos/userprog/exception.c index bc3760f..e5b9ef2 100644 --- a/pintos/userprog/exception.c +++ b/pintos/userprog/exception.c @@ -7,6 +7,7 @@ #include "threads/vaddr.h" #include "intrinsic.h" + /* Number of page faults processed. */ static long long page_fault_cnt; @@ -153,6 +154,15 @@ page_fault (struct intr_frame *f) { return; } + /* my_entry가 NULL이 아닌지 확인하는 안전장치가 있으면 좋습니다. */ + + if (thread_current()->my_entry != NULL) { + thread_current()->my_entry->exit_status = -1; + } + + thread_exit(); + + /* Count page faults. */ page_fault_cnt++; diff --git a/pintos/userprog/process.c b/pintos/userprog/process.c index 7af0d1a..3dc3e30 100644 --- a/pintos/userprog/process.c +++ b/pintos/userprog/process.c @@ -600,7 +600,10 @@ bool lazy_load_segment(struct page *page, void *aux) { if (success) memset(kva + info->page_read_bytes, 0, info->page_zero_bytes); - free (info); + + if (VM_TYPE(page->uninit.type) != VM_FILE) + free(info); + return true; } diff --git a/pintos/userprog/syscall.c b/pintos/userprog/syscall.c index dacc945..8204059 100644 --- a/pintos/userprog/syscall.c +++ b/pintos/userprog/syscall.c @@ -50,6 +50,8 @@ 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 void *syscall_mmap(void *addr, size_t length, int writable, int fd, off_t offset); +static void sys_munmap (void *addr); void syscall_init(void) { write_msr(MSR_STAR, ((uint64_t)SEL_UCSEG - 0x10) << 48 | ((uint64_t)SEL_KCSEG) << 32); @@ -65,7 +67,7 @@ void syscall_init(void) { /* The main system call interface */ void syscall_handler(struct intr_frame* f) { thread_current()->tf = *f; - uint64_t arg1 = f->R.rdi, arg2 = f->R.rsi, arg3 = f->R.rdx; + 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 +114,12 @@ 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; + case SYS_MUNMAP: + sys_munmap(arg1); + break; } } @@ -260,3 +268,27 @@ static int syscall_dup2(int oldfd, int newfd) { lock_release(&file_lock); return result; } + +static void *syscall_mmap(void *addr, size_t length, int writable, int fd, off_t offset) { + struct file *file; + + if (fd == 0 || fd == 1) { + return NULL; + } + + file = get_fd_entry(thread_current(), fd); + if (file == NULL) { + return NULL; + } + + if (addr == 0 || length == 0 || addr == NULL || pg_ofs(addr) || pg_ofs(offset)) { + return NULL; + } + + return do_mmap(addr, length, writable, file, offset); +} + +static void sys_munmap (void *addr) { + + do_munmap(addr); +} diff --git a/pintos/vm/file.c b/pintos/vm/file.c index 5f7eba9..4c4772e 100644 --- a/pintos/vm/file.c +++ b/pintos/vm/file.c @@ -1,6 +1,11 @@ /* file.c: Implementation of memory backed file object (mmaped object). */ #include "vm/vm.h" +#include "threads/vaddr.h" +#include "userprog/process.h" +#include "threads/malloc.h" +#include "threads/mmu.h" + static bool file_backed_swap_in (struct page *page, void *kva); static bool file_backed_swap_out (struct page *page); @@ -19,13 +24,16 @@ void vm_file_init (void) { } -/* Initialize the file backed page */ -bool -file_backed_initializer (struct page *page, enum vm_type type, void *kva) { - /* Set up the handler */ +bool file_backed_initializer (struct page *page, enum vm_type type, void *kva) { page->operations = &file_ops; + lazy_load_info *aux; + + aux = page->uninit.aux; struct file_page *file_page = &page->file; + file_page->aux = aux; + + return true; } /* Swap in the page by read contents from the file. */ @@ -40,19 +48,98 @@ file_backed_swap_out (struct page *page) { struct file_page *file_page UNUSED = &page->file; } -/* Destory the file backed page. PAGE will be freed by the caller. */ -static void -file_backed_destroy (struct page *page) { - struct file_page *file_page UNUSED = &page->file; + +static void file_backed_destroy (struct page *page) { + struct file_page *file_page = &page->file; + lazy_load_info *aux = file_page->aux; + + if (pml4_is_dirty(thread_current()->pml4, page->va)) { + file_write_at(aux->file, page->frame->kva, aux->page_read_bytes, aux->ofs); + pml4_set_dirty(thread_current()->pml4, page->va, 0); + } + + if (aux->file) { + file_close(aux->file); + } + + free(aux); } -/* Do the mmap */ -void * -do_mmap (void *addr, size_t length, int writable, - struct file *file, off_t offset) { +void *do_mmap (void *addr, size_t length, int writable, struct file *file, off_t offset) { + void *cur = addr; + unsigned count = 0; + struct page *head_page = NULL; + + while (cur - addr < length) { + + if (is_kernel_vaddr(cur) || spt_find_page(&thread_current()->spt, cur) != NULL) { + return NULL; + } + + cur += PGSIZE; + count++; + } + + cur = addr; + while (length > 0) { + struct lazy_load_info* aux = malloc(sizeof *aux); + size_t page_read_bytes = length < PGSIZE ? length : PGSIZE; + size_t page_zero_bytes = PGSIZE - page_read_bytes; + + if (aux == NULL) + return NULL; + + aux->file = file_reopen(file); + + if (aux->file == NULL) { + free(aux); + return NULL; + } + + aux->ofs = offset; + aux->page_read_bytes = page_read_bytes; + aux->page_zero_bytes = page_zero_bytes; + + if (!vm_alloc_page_with_initializer(VM_FILE, cur, writable, lazy_load_segment, aux)) { + file_close(aux->file); + free(aux); + return NULL; + } + + if (cur == addr) { + head_page = spt_find_page(&thread_current()->spt, addr); + head_page->page_length = count; + } + + cur += PGSIZE; + offset += page_read_bytes; + length -= page_read_bytes; + } + + return addr; } -/* Do the munmap */ -void -do_munmap (void *addr) { +void do_munmap (void *addr) { + + struct page *head_page; + void *current; + unsigned count; + struct supplemental_page_table *spt; + + spt = &thread_current()->spt; + head_page = spt_find_page(spt, addr); + if (head_page == NULL) { + return; + } + + count = head_page->page_length; + current = addr; + + for (int i = 0; i < count; i++) { + struct page *page = spt_find_page(spt, current); + if (page != NULL) { + spt_remove_page(spt, page); + } + current += PGSIZE; + } }