diff --git a/pintos/include/vm/anon.h b/pintos/include/vm/anon.h index c6b22d7..3599ba7 100644 --- a/pintos/include/vm/anon.h +++ b/pintos/include/vm/anon.h @@ -6,10 +6,10 @@ struct page; enum vm_type; struct anon_page { - size_t swap_idx; + size_t swap_idx; }; -void vm_anon_init (void); -bool anon_initializer (struct page *page, enum vm_type type, void *kva); +void vm_anon_init(void); +bool anon_initializer(struct page* page, enum vm_type type, void* kva); #endif diff --git a/pintos/include/vm/file.h b/pintos/include/vm/file.h index efac388..e474e46 100644 --- a/pintos/include/vm/file.h +++ b/pintos/include/vm/file.h @@ -1,6 +1,7 @@ #ifndef VM_FILE_H #define VM_FILE_H #include + #include "filesys/file.h" struct page; @@ -8,25 +9,24 @@ enum vm_type; struct mmap_file; struct file_page { - struct file *file; + struct file* file; off_t ofs; size_t read_bytes; size_t zero_bytes; - struct mmap_file *mmap; + struct mmap_file* mmap; }; struct mmap_file { - void *start; + void* start; size_t page_cnt; - struct file *file; + struct file* file; off_t offset; struct list_elem elem; }; - -void vm_file_init (void); -bool file_backed_initializer (struct page *page, enum vm_type type, void *kva); -bool lazy_load_file (struct page *page, void *aux); -void *do_mmap(void *addr, size_t length, int writable, struct file *file, off_t offset); -void do_munmap (void *va); +void vm_file_init(void); +bool file_backed_initializer(struct page* page, enum vm_type type, void* kva); +bool lazy_load_file(struct page* page, void* aux); +void* do_mmap(void* addr, size_t length, int writable, struct file* file, off_t offset); +void do_munmap(void* va); #endif diff --git a/pintos/include/vm/vm.h b/pintos/include/vm/vm.h index 3d0da9e..6c70a3c 100644 --- a/pintos/include/vm/vm.h +++ b/pintos/include/vm/vm.h @@ -1,34 +1,35 @@ #ifndef VM_VM_H #define VM_VM_H #include -#include "threads/palloc.h" -#include "lib/kernel/hash.h" + #include "filesys/off_t.h" +#include "lib/kernel/hash.h" +#include "threads/palloc.h" enum vm_type { - /* page not initialized */ - VM_UNINIT = 0, - /* page not related to the file, aka anonymous page */ - VM_ANON = 1, - /* page that realated to the file */ - VM_FILE = 2, - /* page that hold the page cache, for project 4 */ - VM_PAGE_CACHE = 3, - - /* Bit flags to store state */ - - /* Auxillary bit flag marker for store information. You can add more - * markers, until the value is fit in the int. */ - VM_MARKER_0 = (1 << 3), - VM_MARKER_1 = (1 << 4), - - /* DO NOT EXCEED THIS VALUE. */ - VM_MARKER_END = (1 << 31), + /* page not initialized */ + VM_UNINIT = 0, + /* page not related to the file, aka anonymous page */ + VM_ANON = 1, + /* page that realated to the file */ + VM_FILE = 2, + /* page that hold the page cache, for project 4 */ + VM_PAGE_CACHE = 3, + + /* Bit flags to store state */ + + /* Auxillary bit flag marker for store information. You can add more + * markers, until the value is fit in the int. */ + VM_MARKER_0 = (1 << 3), + VM_MARKER_1 = (1 << 4), + + /* DO NOT EXCEED THIS VALUE. */ + VM_MARKER_END = (1 << 31), }; -#include "vm/uninit.h" #include "vm/anon.h" #include "vm/file.h" +#include "vm/uninit.h" #ifdef EFILESYS #include "filesys/page_cache.h" #endif @@ -44,30 +45,31 @@ struct file; * uninit_page, file_page, anon_page, and page cache (project4). * DO NOT REMOVE/MODIFY PREDEFINED MEMBER OF THIS STRUCTURE. */ struct page { - const struct page_operations *operations; - void *va; /* Address in terms of user space */ - struct frame *frame; /* Back reference for frame */ - - /* Your implementation */ - struct hash_elem hash_elem; - bool writable; - - /* Per-type data are binded into the union. - * Each function automatically detects the current union */ - union { - struct uninit_page uninit; - struct anon_page anon; - struct file_page file; + const struct page_operations* operations; + void* va; /* Address in terms of user space */ + struct frame* frame; /* Back reference for frame */ + + /* Your implementation */ + struct hash_elem hash_elem; + bool writable; + + /* Per-type data are binded into the union. + * Each function automatically detects the current union */ + union { + struct uninit_page uninit; + struct anon_page anon; + struct file_page file; #ifdef EFILESYS - struct page_cache page_cache; + struct page_cache page_cache; #endif - }; + }; }; /* The representation of "frame" */ struct frame { - void *kva; - struct page *page; + void* kva; + struct page* page; + struct list_elem frame_table_elem; }; /* The function table for page operations. @@ -75,44 +77,42 @@ struct frame { * Put the table of "method" into the struct's member, and * call it whenever you needed. */ struct page_operations { - bool (*swap_in) (struct page *, void *); - bool (*swap_out) (struct page *); - void (*destroy) (struct page *); - enum vm_type type; + bool (*swap_in)(struct page*, void*); + bool (*swap_out)(struct page*); + void (*destroy)(struct page*); + enum vm_type type; }; -#define swap_in(page, v) (page)->operations->swap_in ((page), v) -#define swap_out(page) (page)->operations->swap_out (page) +#define swap_in(page, v) (page)->operations->swap_in((page), v) +#define swap_out(page) (page)->operations->swap_out(page) #define destroy(page) \ - if ((page)->operations->destroy) (page)->operations->destroy (page) + if ((page)->operations->destroy) (page)->operations->destroy(page) /* Representation of current process's memory space. * We don't want to force you to obey any specific design for this struct. * All designs up to you for this. */ struct supplemental_page_table { - struct hash hash_table; + struct hash hash_table; }; #include "threads/thread.h" -void supplemental_page_table_init (struct supplemental_page_table *spt); -bool supplemental_page_table_copy (struct supplemental_page_table *dst, - struct supplemental_page_table *src); -void supplemental_page_table_kill (struct supplemental_page_table *spt); -struct page *spt_find_page (struct supplemental_page_table *spt, - void *va); -bool spt_insert_page (struct supplemental_page_table *spt, struct page *page); -bool spt_remove_page (struct supplemental_page_table *spt, struct page *page); - -void vm_init (void); -bool vm_try_handle_fault (struct intr_frame *f, void *addr, bool user, - bool write, bool not_present); +void supplemental_page_table_init(struct supplemental_page_table* spt); +bool supplemental_page_table_copy(struct supplemental_page_table* dst, + struct supplemental_page_table* src); +void supplemental_page_table_kill(struct supplemental_page_table* spt); +struct page* spt_find_page(struct supplemental_page_table* spt, void* va); +bool spt_insert_page(struct supplemental_page_table* spt, struct page* page); +bool spt_remove_page(struct supplemental_page_table* spt, struct page* page); + +void vm_init(void); +bool vm_try_handle_fault(struct intr_frame* f, void* addr, bool user, bool write, bool not_present); #define vm_alloc_page(type, upage, writable) \ - vm_alloc_page_with_initializer ((type), (upage), (writable), NULL, NULL) -bool vm_alloc_page_with_initializer (enum vm_type type, void *upage, - bool writable, vm_initializer *init, void *aux); -void vm_dealloc_page (struct page *page); -bool vm_claim_page (void *va); -enum vm_type page_get_type (struct page *page); - -#endif /* VM_VM_H */ + vm_alloc_page_with_initializer((type), (upage), (writable), NULL, NULL) +bool vm_alloc_page_with_initializer(enum vm_type type, void* upage, bool writable, + vm_initializer* init, void* aux); +void vm_dealloc_page(struct page* page); +bool vm_claim_page(void* va); +enum vm_type page_get_type(struct page* page); + +#endif /* VM_VM_H */ diff --git a/pintos/vm/anon.c b/pintos/vm/anon.c index 75a24c3..c02a6df 100644 --- a/pintos/vm/anon.c +++ b/pintos/vm/anon.c @@ -1,63 +1,105 @@ /* anon.c: Implementation of page for non-disk image (a.k.a. anonymous page). */ -#include "vm/vm.h" #include "devices/disk.h" +#include "vm/vm.h" +#define SECTORS_PER_PAGE 8 + +#include "lib/kernel/bitmap.h" +#include "threads/malloc.h" +#include "threads/mmu.h" /* DO NOT MODIFY BELOW LINE */ -static struct disk *swap_disk; -static bool anon_swap_in (struct page *page, void *kva); -static bool anon_swap_out (struct page *page); -static void anon_destroy (struct page *page); +static struct disk* swap_disk; +static bool anon_swap_in(struct page* page, void* kva); +static bool anon_swap_out(struct page* page); +static void anon_destroy(struct page* page); + +static struct disk* swap_disk; +static struct bitmap* swap_bitmap; /* DO NOT MODIFY this struct */ static const struct page_operations anon_ops = { - .swap_in = anon_swap_in, - .swap_out = anon_swap_out, - .destroy = anon_destroy, - .type = VM_ANON, + .swap_in = anon_swap_in, + .swap_out = anon_swap_out, + .destroy = anon_destroy, + .type = VM_ANON, }; /* Initialize the data for anonymous pages */ -void vm_anon_init (void) { - swap_disk = disk_get (1, 1); +void vm_anon_init(void) { + swap_disk = disk_get(1, 1); + size_t swap_size = disk_size(swap_disk) / SECTORS_PER_PAGE; + swap_bitmap = bitmap_create(swap_size); } /* Initialize the file mapping */ -bool anon_initializer (struct page *page, enum vm_type type, void *kva) { - struct anon_page *anon_page; - page->operations = &anon_ops; - // anon_page = &page->anon; - // anon_page->swap_idx = BITMAP_ERROR; - return true; +bool anon_initializer(struct page* page, enum vm_type type, void* kva) { + struct anon_page* anon_page = &page->anon; + page->operations = &anon_ops; + anon_page->swap_idx = BITMAP_ERROR; + return true; } /* Swap in the page by read contents from the swap disk. */ -static bool -anon_swap_in (struct page *page, void *kva) { - ASSERT (page != NULL); - ASSERT (page->frame != NULL); - return true; +static bool anon_swap_in(struct page* page, void* kva) { + ASSERT(page != NULL); + ASSERT(page->frame != NULL); + + struct anon_page* anon_page = &page->anon; + + size_t swap_slot_idx = anon_page->swap_idx; + + if (swap_bitmap == NULL || !bitmap_test(swap_bitmap, swap_slot_idx)) + return false; + + for (int i = 0; i < SECTORS_PER_PAGE; i++) { + disk_sector_t sec_no = (swap_slot_idx * SECTORS_PER_PAGE) + i; + void* buffer = kva + (DISK_SECTOR_SIZE * i); + disk_read(swap_disk, sec_no, buffer); + } + + bitmap_set(swap_bitmap, swap_slot_idx, false); + + anon_page->swap_idx = BITMAP_ERROR; + + return true; } /* Swap out the page by writing contents to the swap disk. */ -static bool -anon_swap_out (struct page *page) { - ASSERT (page != NULL); - return true; +static bool anon_swap_out(struct page* page) { + struct anon_page* anon_page = &page->anon; + + size_t swap_slot_idx = bitmap_scan_and_flip(swap_bitmap, 0, 1, false); + + if (swap_slot_idx == BITMAP_ERROR) + return false; + + for (int i = 0; i < SECTORS_PER_PAGE; i++) { + disk_sector_t sec_no = (swap_slot_idx * SECTORS_PER_PAGE) + i; + + void* buffer = page->frame->kva + (DISK_SECTOR_SIZE * i); + + disk_write(swap_disk, sec_no, buffer); + } + + anon_page->swap_idx = swap_slot_idx; + + return true; } /* Destroy the anonymous page. PAGE will be freed by the caller. */ -static void anon_destroy (struct page *page) { - struct anon_page *anon_page = &page->anon; +static void anon_destroy(struct page* page) { + struct anon_page* anon_page = &page->anon; - ASSERT (page != NULL); + ASSERT(page != NULL); - if (page->frame != NULL) { - struct thread *t = thread_current (); + if (page->frame != NULL) { + struct thread* t = thread_current(); - pml4_clear_page (t->pml4, page->va); - palloc_free_page (page->frame->kva); - free (page->frame); - page->frame = NULL; - } + pml4_clear_page(t->pml4, page->va); + palloc_free_page(page->frame->kva); + list_remove(&page->frame->frame_table_elem); + free(page->frame); + page->frame = NULL; + } } diff --git a/pintos/vm/file.c b/pintos/vm/file.c index 01d368e..ae94c5d 100644 --- a/pintos/vm/file.c +++ b/pintos/vm/file.c @@ -1,203 +1,216 @@ /* file.c: Implementation of memory backed file object (mmaped object). */ +#include "vm/file.h" + #include #include + #include "threads/malloc.h" #include "threads/mmu.h" #include "threads/palloc.h" #include "threads/thread.h" #include "threads/vaddr.h" -#include "vm/vm.h" -#include "vm/file.h" #include "userprog/syscall.h" +#include "vm/vm.h" -static bool file_backed_swap_in (struct page *page, void *kva); -static bool file_backed_swap_out (struct page *page); -static void file_backed_destroy (struct page *page); -bool lazy_load_file (struct page *page, void *aux); -static struct mmap_file *find_mmap (struct thread *t, void *addr); +static bool file_backed_swap_in(struct page* page, void* kva); +static bool file_backed_swap_out(struct page* page); +static void file_backed_destroy(struct page* page); +bool lazy_load_file(struct page* page, void* aux); +static struct mmap_file* find_mmap(struct thread* t, void* addr); /* DO NOT MODIFY this struct */ static const struct page_operations file_ops = { - .swap_in = file_backed_swap_in, - .swap_out = file_backed_swap_out, - .destroy = file_backed_destroy, - .type = VM_FILE, + .swap_in = file_backed_swap_in, + .swap_out = file_backed_swap_out, + .destroy = file_backed_destroy, + .type = VM_FILE, }; /* The initializer of file vm */ -void -vm_file_init (void) { -} +void vm_file_init(void) {} /* Initialize the file backed page */ -bool file_backed_initializer (struct page *page, enum vm_type type, void *kva) { - page->operations = &file_ops; - return true; +bool file_backed_initializer(struct page* page, enum vm_type type, void* kva) { + page->operations = &file_ops; + return true; } /* Swap in the page by read contents from the file. */ -static bool file_backed_swap_in (struct page *page, void *kva) { - struct file_page *file_page = &page->file; - off_t ofs; - size_t page_read_bytes; +static bool file_backed_swap_in(struct page* page, void* kva) { + struct file_page* file_page = &page->file; + off_t ofs; + size_t page_read_bytes; - ASSERT (page != NULL); - ASSERT (kva != NULL); + ASSERT(page != NULL); + ASSERT(kva != NULL); - ofs = file_page->ofs; - page_read_bytes = file_page->read_bytes; + ofs = file_page->ofs; + page_read_bytes = file_page->read_bytes; - lock_acquire (&file_lock); - off_t bytes_read = file_read_at (file_page->file, kva, page_read_bytes, ofs); - lock_release (&file_lock); + lock_acquire(&file_lock); + off_t bytes_read = file_read_at(file_page->file, kva, page_read_bytes, ofs); + lock_release(&file_lock); - if (bytes_read != (off_t) page_read_bytes) - return false; + if (bytes_read != (off_t)page_read_bytes) + return false; - memset (kva + page_read_bytes, 0, file_page->zero_bytes); - return true; + memset(kva + page_read_bytes, 0, file_page->zero_bytes); + return true; } /* Swap out the page by writeback contents to the file. */ -static bool file_backed_swap_out (struct page *page) { - struct frame *frame = page->frame; - struct thread *t = thread_current (); - struct file_page *file_page = &page->file; - - if (frame == NULL) - return true; - - if (file_page->read_bytes > 0 && pml4_is_dirty (t->pml4, page->va)) { - lock_acquire (&file_lock); - file_write_at (file_page->file, frame->kva, file_page->read_bytes, file_page->ofs); - lock_release (&file_lock); - } - - pml4_clear_page (t->pml4, page->va); - // palloc_free_page (frame->kva); - // free (frame); - page->frame = NULL; - return true; +static bool file_backed_swap_out(struct page* page) { + struct frame* frame = page->frame; + struct thread* t = thread_current(); + struct file_page* file_page = &page->file; + + if (frame == NULL) + return true; + + if (file_page->read_bytes > 0 && pml4_is_dirty(t->pml4, page->va)) { + lock_acquire(&file_lock); + file_write_at(file_page->file, frame->kva, file_page->read_bytes, file_page->ofs); + lock_release(&file_lock); + } + + return true; } /* Destory the file backed page. PAGE will be freed by the caller. */ -static void file_backed_destroy (struct page *page) { - file_backed_swap_out (page); +static void file_backed_destroy(struct page* page) { + struct file_page* file_page UNUSED = &page->file; + + if (page->frame != NULL) { + if (pml4_is_dirty(thread_current()->pml4, page->va)) { + file_backed_swap_out(page); + } + + struct frame* frame = page->frame; + + pml4_clear_page(thread_current()->pml4, page->va); + + list_remove(&frame->frame_table_elem); + + palloc_free_page(frame->kva); + + free(frame); + + page->frame = NULL; + } } -void *do_mmap (void *addr, size_t length, int writable, struct file *file, off_t offset) { - struct thread *t = thread_current (); - size_t page_cnt = DIV_ROUND_UP (length, PGSIZE); - void *upage = addr; - struct mmap_file *map; - off_t file_len = file_length (file); - - for (size_t i = 0; i < page_cnt; i++, upage += PGSIZE) { - if (spt_find_page (&t->spt, upage) != NULL) - goto fail_file; - } - - map = calloc (1, sizeof *map); - - if (map == NULL) - goto fail_file; - - map->start = addr; - map->page_cnt = page_cnt; - map->file = file; - map->offset = offset; - list_push_back (&t->mmap_list, &map->elem); - - upage = addr; - for (size_t i = 0; i < page_cnt; i++, upage += PGSIZE) { - off_t cur_ofs = offset + i * PGSIZE; - size_t read_bytes = 0; - - if (cur_ofs < file_len) { - size_t file_left = file_len - cur_ofs; - read_bytes = file_left >= PGSIZE ? PGSIZE : file_left; - } - - size_t zero_bytes = PGSIZE - read_bytes; - struct file_page *aux = malloc (sizeof *aux); - - if (aux == NULL) - goto fail_map; - - aux->file = file; - aux->ofs = offset + i * PGSIZE; - aux->read_bytes = read_bytes; - aux->zero_bytes = zero_bytes; - aux->mmap = map; - - if (!vm_alloc_page_with_initializer (VM_FILE, upage, writable, lazy_load_file, aux)) { - free (aux); - goto fail_map; - } - } - return addr; +void* do_mmap(void* addr, size_t length, int writable, struct file* file, off_t offset) { + struct thread* t = thread_current(); + size_t page_cnt = DIV_ROUND_UP(length, PGSIZE); + void* upage = addr; + struct mmap_file* map; + off_t file_len = file_length(file); + + for (size_t i = 0; i < page_cnt; i++, upage += PGSIZE) { + if (spt_find_page(&t->spt, upage) != NULL) + goto fail_file; + } + + map = calloc(1, sizeof *map); + + if (map == NULL) + goto fail_file; + + map->start = addr; + map->page_cnt = page_cnt; + map->file = file; + map->offset = offset; + list_push_back(&t->mmap_list, &map->elem); + + upage = addr; + for (size_t i = 0; i < page_cnt; i++, upage += PGSIZE) { + off_t cur_ofs = offset + i * PGSIZE; + size_t read_bytes = 0; + + if (cur_ofs < file_len) { + size_t file_left = file_len - cur_ofs; + read_bytes = file_left >= PGSIZE ? PGSIZE : file_left; + } + + size_t zero_bytes = PGSIZE - read_bytes; + struct file_page* aux = malloc(sizeof *aux); + + if (aux == NULL) + goto fail_map; + + aux->file = file; + aux->ofs = offset + i * PGSIZE; + aux->read_bytes = read_bytes; + aux->zero_bytes = zero_bytes; + aux->mmap = map; + + if (!vm_alloc_page_with_initializer(VM_FILE, upage, writable, lazy_load_file, aux)) { + free(aux); + goto fail_map; + } + } + return addr; fail_map: - do_munmap (addr); - return NULL; + do_munmap(addr); + return NULL; fail_file: - lock_acquire (&file_lock); - file_close (file); - lock_release (&file_lock); - return NULL; + lock_acquire(&file_lock); + file_close(file); + lock_release(&file_lock); + return NULL; } - /* Do the munmap */ -void do_munmap (void *addr) { - struct thread *t = thread_current (); - struct mmap_file *target; +void do_munmap(void* addr) { + struct thread* t = thread_current(); + struct mmap_file* target; - if (addr == NULL) - return; + if (addr == NULL) + return; - target = find_mmap (t, addr); - if (target == NULL) - return; + target = find_mmap(t, addr); + if (target == NULL) + return; - void *upage = target->start; - for (size_t i = 0; i < target->page_cnt; i++, upage += PGSIZE) { - struct page *page = spt_find_page (&t->spt, upage); + void* upage = target->start; + for (size_t i = 0; i < target->page_cnt; i++, upage += PGSIZE) { + struct page* page = spt_find_page(&t->spt, upage); - if (page == NULL) - continue; + if (page == NULL) + continue; - spt_remove_page (&t->spt, page); - } + spt_remove_page(&t->spt, page); + } - lock_acquire (&file_lock); - file_close (target->file); - lock_release (&file_lock); - list_remove (&target->elem); - free (target); + lock_acquire(&file_lock); + file_close(target->file); + lock_release(&file_lock); + list_remove(&target->elem); + free(target); } -bool lazy_load_file (struct page *page, void *aux) { - struct file_page *dst = &page->file; - struct file_page *src = aux; +bool lazy_load_file(struct page* page, void* aux) { + struct file_page* dst = &page->file; + struct file_page* src = aux; - ASSERT (src != NULL); - ASSERT (page->frame != NULL); + ASSERT(src != NULL); + ASSERT(page->frame != NULL); - *dst = *src; - free (src); - return file_backed_swap_in (page, page->frame->kva); + *dst = *src; + free(src); + return file_backed_swap_in(page, page->frame->kva); } -static struct mmap_file *find_mmap (struct thread *t, void *addr) { - struct list_elem *e = list_begin (&t->mmap_list); +static struct mmap_file* find_mmap(struct thread* t, void* addr) { + struct list_elem* e = list_begin(&t->mmap_list); - while (e != list_end (&t->mmap_list)) { - struct mmap_file *map = list_entry (e, struct mmap_file, elem); - if (map->start == addr) - return map; - e = list_next (e); - } - return NULL; + while (e != list_end(&t->mmap_list)) { + struct mmap_file* map = list_entry(e, struct mmap_file, elem); + if (map->start == addr) + return map; + e = list_next(e); + } + return NULL; } diff --git a/pintos/vm/vm.c b/pintos/vm/vm.c index c6c07b8..f59a57c 100644 --- a/pintos/vm/vm.c +++ b/pintos/vm/vm.c @@ -1,168 +1,205 @@ /* vm.c: Generic interface for virtual memory objects. */ +#include "vm/vm.h" + #include + +#include "filesys/file.h" +#include "lib/kernel/list.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" #include "vm/file.h" +#include "vm/inspect.h" + +static struct list frame_table; +static struct list_elem* clock_elem; + /* 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. */ + list_init(&frame_table); + clock_elem = NULL; } /* 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 bool vm_stack_growth (void *addr); -static void spt_destroy_page (struct hash_elem *elem, void *aux); -static bool copy_uninit_page (struct supplemental_page_table *dst, struct page *src_page); -static bool copy_anon_page (struct supplemental_page_table *dst, struct page *src_page); -static bool copy_file_page(struct supplemental_page_table *dst_spt, struct page *src_page); +static struct frame* vm_get_victim(void); +static struct frame* vm_get_frame(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 bool vm_stack_growth(void* addr); +static void spt_destroy_page(struct hash_elem* elem, void* aux); +static bool copy_uninit_page(struct supplemental_page_table* dst, struct page* src_page); +static bool copy_anon_page(struct supplemental_page_table* dst, struct page* src_page); +static bool copy_file_page(struct supplemental_page_table* dst_spt, struct page* src_page); #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; + 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* candidate = NULL; + struct thread* curr = thread_current(); - return victim; -} + if (list_empty(&frame_table)) + PANIC("Frame table is empty!"); + + if (clock_elem == NULL || clock_elem == list_end(&frame_table)) { + clock_elem = list_begin(&frame_table); + } + + while (true) { + candidate = list_entry(clock_elem, struct frame, frame_table_elem); + clock_elem = list_next(clock_elem); + if (clock_elem == list_end(&frame_table)) { + clock_elem = list_begin(&frame_table); + } + + struct page* p = candidate->page; + + if (pml4_is_accessed(curr->pml4, p->va)) + pml4_set_accessed(curr->pml4, p->va, 0); + else + return candidate; + } +} /* 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. */ +struct frame* vm_evict_frame(void) { + struct frame* victim = vm_get_victim(); + struct page* page = victim->page; - return NULL; -} + // [2] 짐 싸서 내보내기 (Swap Out) + if (swap_out(page) == false) + PANIC("Swap out failed!"); + + page->frame = NULL; + victim->page = NULL; + + pml4_clear_page(thread_current()->pml4, page->va); + return victim; +} /* 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) { - PANIC("todo"); + // PANIC("todo"); + frame = vm_evict_frame(); + frame->page = NULL; + return frame; } frame = malloc(sizeof(struct frame)); @@ -174,215 +211,214 @@ static struct frame * vm_get_frame (void) { frame->kva = kva; frame->page = NULL; - ASSERT (frame != NULL); - ASSERT (frame->page == NULL); + list_push_back(&frame_table, &frame->frame_table_elem); + + ASSERT(frame != NULL); + ASSERT(frame->page == NULL); return frame; } -static bool vm_stack_growth (void *addr) { - struct supplemental_page_table *spt; - void *stack_bottom = pg_round_down (addr); +static bool vm_stack_growth(void* addr) { + struct supplemental_page_table* spt; + void* stack_bottom = pg_round_down(addr); - spt = &thread_current ()->spt; + spt = &thread_current()->spt; - if (spt_find_page (spt, stack_bottom) != NULL) - return true; - - return vm_alloc_page(VM_ANON | VM_MARKER_0, stack_bottom, true); + if (spt_find_page(spt, stack_bottom) != NULL) + return true; + + return vm_alloc_page(VM_ANON | VM_MARKER_0, stack_bottom, true); } /* Handle the fault on write_protected page */ -static bool -vm_handle_wp (struct page *page UNUSED) { -} +static bool vm_handle_wp(struct page* page UNUSED) { return false; } -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; - void *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; + void* page_addr; - spt = &thread_current ()->spt; + spt = &thread_current()->spt; - if (addr == NULL || is_kernel_vaddr (addr) || !not_present) - return false; + if (addr == NULL || is_kernel_vaddr(addr) || !not_present) + return false; - page_addr = pg_round_down (addr); - page = spt_find_page (spt, page_addr); + page_addr = pg_round_down(addr); + page = spt_find_page(spt, page_addr); - if (page == NULL) { - if (!should_grow_stack (f, addr, user) || !vm_stack_growth (page_addr)) - return false; + if (page == NULL) { + if (!should_grow_stack(f, addr, user) || !vm_stack_growth(page_addr)) + return false; - page = spt_find_page (spt, page_addr); - - if (page == NULL) - return false; - } + page = spt_find_page(spt, page_addr); - if (write && !page->writable) - return false; + if (page == NULL) + return false; + } - return vm_do_claim_page (page); -} + if (write && !page->writable) + return false; + return vm_do_claim_page(page); +} /* 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); +bool vm_claim_page(void* va) { + struct page* page = NULL; - if (page == NULL) - return false; + page = spt_find_page(&thread_current()->spt, va); - return vm_do_claim_page (page); + 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)){ - palloc_free_page(frame->kva); - free(frame); - page->frame = NULL; - return false; - } - - return swap_in (page, frame->kva); + if (!pml4_set_page(thread_current()->pml4, page->va, frame->kva, page->writable)) { + palloc_free_page(frame->kva); + free(frame); + page->frame = NULL; + 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 *src_page; - enum vm_type type; - - src_page = hash_entry (hash_cur (&i), struct page, hash_elem); - type = page_get_type (src_page); - - switch (type) { - - case VM_UNINIT: - if (!copy_uninit_page (dst, src_page)) - return false; - break; - - case VM_ANON: - if (!copy_anon_page (dst, src_page)) - return false; - break; - - case VM_FILE: - if (!copy_file_page(dst, src_page)) - return false; - 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* src_page; + enum vm_type type; + + src_page = hash_entry(hash_cur(&i), struct page, hash_elem); + type = page_get_type(src_page); + + switch (type) { + case VM_UNINIT: + if (!copy_uninit_page(dst, src_page)) + return false; + break; + + case VM_ANON: + if (!copy_anon_page(dst, src_page)) + return false; + break; + + case VM_FILE: + if (!copy_file_page(dst, src_page)) + return false; + break; + + default: + break; + } + } - return true; + return true; } -static bool copy_uninit_page (struct supplemental_page_table *dst, struct page *src_page) { - struct uninit_page *uninit = &src_page->uninit; - void *aux = uninit->aux; - lazy_load_info *dst_info = NULL; +static bool copy_uninit_page(struct supplemental_page_table* dst, struct page* src_page) { + struct uninit_page* uninit = &src_page->uninit; + void* aux = uninit->aux; + lazy_load_info* dst_info = NULL; - if (aux != NULL) { - lazy_load_info *src_info = aux; - dst_info = malloc (sizeof *dst_info); + if (aux != NULL) { + lazy_load_info* src_info = aux; + dst_info = malloc(sizeof *dst_info); - if (dst_info == NULL) - return false; - - memcpy (dst_info, src_info, sizeof *dst_info); + if (dst_info == NULL) + return false; - if (src_info->file != NULL) { - dst_info->file = file_reopen (src_info->file); - if (dst_info->file == NULL) - goto fail; - } - aux = dst_info; - } + memcpy(dst_info, src_info, sizeof *dst_info); - if (!vm_alloc_page_with_initializer (uninit->type, src_page->va, src_page->writable, uninit->init, aux)) - goto fail; + if (src_info->file != NULL) { + dst_info->file = file_reopen(src_info->file); + if (dst_info->file == NULL) + goto fail; + } + aux = dst_info; + } + + if (!vm_alloc_page_with_initializer(uninit->type, src_page->va, src_page->writable, + uninit->init, aux)) + goto fail; - return true; + return true; fail: - if (dst_info != NULL) { - if (dst_info->file != NULL) - file_close (dst_info->file); - free (dst_info); - } - return false; + if (dst_info != NULL) { + if (dst_info->file != NULL) + file_close(dst_info->file); + free(dst_info); + } + return false; } +static bool copy_anon_page(struct supplemental_page_table* dst, struct page* src_page) { + struct page* dst_page; -static bool copy_anon_page (struct supplemental_page_table *dst, struct page *src_page) { - struct page *dst_page; - - if (!vm_alloc_page (VM_ANON, src_page->va, src_page->writable)) - return false; + if (!vm_alloc_page(VM_ANON, src_page->va, src_page->writable)) + return false; - if (src_page->frame == NULL) - return true; + if (src_page->frame == NULL) + return true; - if (!vm_claim_page (src_page->va)) - return false; + if (!vm_claim_page(src_page->va)) + return false; - dst_page = spt_find_page (dst, src_page->va); - memcpy (dst_page->frame->kva, src_page->frame->kva, PGSIZE); - return true; + dst_page = spt_find_page(dst, src_page->va); + memcpy(dst_page->frame->kva, src_page->frame->kva, PGSIZE); + return true; } -static bool copy_file_page(struct supplemental_page_table *dst_spt, struct page *src_page){ - void *va = src_page->va; +static bool copy_file_page(struct supplemental_page_table* dst_spt, struct page* src_page) { + void* va = src_page->va; bool writable = src_page->writable; - struct file_page *src_fp = &src_page->file; + struct file_page* src_fp = &src_page->file; - struct file_page *aux = malloc(sizeof *aux); + struct file_page* aux = malloc(sizeof *aux); if (aux == NULL) return false; - *aux = *src_fp; + *aux = *src_fp; if (!vm_alloc_page_with_initializer(VM_FILE, va, writable, lazy_load_file, aux)) { free(aux); return false; } - struct page *child_page = spt_find_page(dst_spt, va); + struct page* child_page = spt_find_page(dst_spt, va); if (child_page == NULL) - return false; + return false; if (src_page->frame != NULL) { if (!vm_claim_page(va)) @@ -394,46 +430,46 @@ static bool copy_file_page(struct supplemental_page_table *dst_spt, struct page 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); - vm_dealloc_page (page); + 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; - rsp = user ? (uint8_t *) f->rsp : (uint8_t *) thread_current ()->tf.rsp; + rsp = user ? (uint8_t*)f->rsp : (uint8_t*)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; + if (fault_addr < (uint8_t*)USER_STACK - STACK_LIMIT) + return false; - if (fault_addr < rsp - STACK_HEURISTIC) - return false; + if (fault_addr < rsp - STACK_HEURISTIC) + return false; - return true; + return true; } diff --git a/vm.c b/vm.c deleted file mode 100644 index c6c07b8..0000000 --- a/vm.c +++ /dev/null @@ -1,439 +0,0 @@ -/* vm.c: Generic interface for virtual memory objects. */ - -#include -#include "threads/malloc.h" -#include "threads/vaddr.h" -#include "threads/mmu.h" -#include "threads/thread.h" -#include "userprog/process.h" -#include "vm/vm.h" -#include "vm/inspect.h" -#include "filesys/file.h" -#include "vm/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 (); -#endif - 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; - } -} - -/* 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 bool vm_stack_growth (void *addr); -static void spt_destroy_page (struct hash_elem *elem, void *aux); -static bool copy_uninit_page (struct supplemental_page_table *dst, struct page *src_page); -static bool copy_anon_page (struct supplemental_page_table *dst, struct page *src_page); -static bool copy_file_page(struct supplemental_page_table *dst_spt, struct page *src_page); - -#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; - } -err: - 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; - - if (spt == NULL || va == NULL) - return NULL; - - 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); -} - -/* 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; - - // 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; - - if (spt == NULL || page == NULL) - return false; - - result = hash_delete(&spt->hash_table, &page->hash_elem); - - 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. */ - - 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. */ - - 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; - - kva = palloc_get_page(PAL_USER); - if (kva == NULL) { - PANIC("todo"); - } - - frame = malloc(sizeof(struct frame)); - if (frame == NULL) { - palloc_free_page(kva); - return NULL; - } - - frame->kva = kva; - frame->page = NULL; - - ASSERT (frame != NULL); - ASSERT (frame->page == NULL); - return frame; -} - -static bool vm_stack_growth (void *addr) { - struct supplemental_page_table *spt; - void *stack_bottom = pg_round_down (addr); - - spt = &thread_current ()->spt; - - if (spt_find_page (spt, stack_bottom) != NULL) - return true; - - return vm_alloc_page(VM_ANON | VM_MARKER_0, stack_bottom, true); -} - -/* Handle the fault on write_protected page */ -static bool -vm_handle_wp (struct page *page UNUSED) { -} - -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; - void *page_addr; - - spt = &thread_current ()->spt; - - if (addr == NULL || is_kernel_vaddr (addr) || !not_present) - return false; - - page_addr = pg_round_down (addr); - page = spt_find_page (spt, page_addr); - - if (page == NULL) { - if (!should_grow_stack (f, addr, user) || !vm_stack_growth (page_addr)) - return false; - - page = spt_find_page (spt, page_addr); - - if (page == NULL) - return false; - } - - if (write && !page->writable) - return false; - - return vm_do_claim_page (page); -} - - -/* Free the page. - * DO NOT MODIFY THIS FUNCTION. */ -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); -} - -/* 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 (); - frame->page = page; - page->frame = frame; - - if (!pml4_set_page(thread_current()->pml4, page->va, frame->kva, page->writable)){ - palloc_free_page(frame->kva); - free(frame); - page->frame = NULL; - 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); -} - -/* 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 *src_page; - enum vm_type type; - - src_page = hash_entry (hash_cur (&i), struct page, hash_elem); - type = page_get_type (src_page); - - switch (type) { - - case VM_UNINIT: - if (!copy_uninit_page (dst, src_page)) - return false; - break; - - case VM_ANON: - if (!copy_anon_page (dst, src_page)) - return false; - break; - - case VM_FILE: - if (!copy_file_page(dst, src_page)) - return false; - break; - - default: - break; - } - } - - return true; -} - -static bool copy_uninit_page (struct supplemental_page_table *dst, struct page *src_page) { - struct uninit_page *uninit = &src_page->uninit; - void *aux = uninit->aux; - lazy_load_info *dst_info = NULL; - - if (aux != NULL) { - lazy_load_info *src_info = aux; - dst_info = malloc (sizeof *dst_info); - - if (dst_info == NULL) - return false; - - memcpy (dst_info, src_info, sizeof *dst_info); - - if (src_info->file != NULL) { - dst_info->file = file_reopen (src_info->file); - if (dst_info->file == NULL) - goto fail; - } - aux = dst_info; - } - - if (!vm_alloc_page_with_initializer (uninit->type, src_page->va, src_page->writable, uninit->init, aux)) - goto fail; - - return true; - -fail: - if (dst_info != NULL) { - if (dst_info->file != NULL) - file_close (dst_info->file); - free (dst_info); - } - return false; -} - - -static bool copy_anon_page (struct supplemental_page_table *dst, struct page *src_page) { - struct page *dst_page; - - if (!vm_alloc_page (VM_ANON, src_page->va, src_page->writable)) - return false; - - if (src_page->frame == NULL) - return true; - - if (!vm_claim_page (src_page->va)) - return false; - - dst_page = spt_find_page (dst, src_page->va); - memcpy (dst_page->frame->kva, src_page->frame->kva, PGSIZE); - return true; -} - -static bool copy_file_page(struct supplemental_page_table *dst_spt, struct page *src_page){ - void *va = src_page->va; - bool writable = src_page->writable; - struct file_page *src_fp = &src_page->file; - - struct file_page *aux = malloc(sizeof *aux); - if (aux == NULL) - return false; - - *aux = *src_fp; - - if (!vm_alloc_page_with_initializer(VM_FILE, va, writable, lazy_load_file, aux)) { - free(aux); - return false; - } - - struct page *child_page = spt_find_page(dst_spt, va); - if (child_page == NULL) - return false; - - if (src_page->frame != NULL) { - if (!vm_claim_page(va)) - return false; - - memcpy(child_page->frame->kva, src_page->frame->kva, PGSIZE); - } - - return true; -} - -void supplemental_page_table_kill (struct supplemental_page_table *spt UNUSED) { - if (spt == NULL) - return; - - 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); - - 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 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; - - rsp = user ? (uint8_t *) f->rsp : (uint8_t *) thread_current ()->tf.rsp; - - if (fault_addr >= (uint8_t *) USER_STACK) - return false; - - if (fault_addr < (uint8_t *) USER_STACK - STACK_LIMIT) - return false; - - if (fault_addr < rsp - STACK_HEURISTIC) - return false; - - return true; -}