๐ฉ๐ปโ๐ป GITHUB ๋ ํฌ์งํ ๋ฆฌ
๐ฉ๐ปโ๐ป GITHUB Anonymous Page ์ด์
๐ก Anonymous page๋ผ๊ณ ๋ถ๋ฆฌ๋ non-disk based image๋ฅผ ๊ตฌํํ๋ค.
ํ์ผ์ ๊ธฐ๋ฐ์ผ๋ก ํ๋ file-backed page์ ๋ฌ๋ฆฌ, ์ด๋ฆ์ด ์ง์ ๋ ํ์ผ ์์ค๊ฐ ์๊ธฐ ๋๋ฌธ์ anonymous๋ผ๊ณ ๋ถ๋ฆฌ๋ฉฐ, ์คํ๊ณผ ํ ์์ญ์์ ์ฌ์ฉ๋๋ค.
anon-page
๋ include/vm/anon.h
์ ์ ์ธ๋์ด์๋ค.Demanding Paging ์ด๋ผ๊ณ ๋ ํ๋ค.
์ง์ฐ ๋ก๋ฉ(lazy loading)์ ํ์์์ ๊น์ง ๋ฉ๋ชจ๋ฆฌ์ ๋ก๋ฉ์ ์ง์ฐ์ํจ๋ค. -> ์ค์ ๋ด์ฉ์ด ๋ก๋๋๋ ์์ ์ page fault๊ฐ ๋ฐ์ํ ๋!
ํ์ด์ง๊ฐ ํ ๋น๋์๋ค๋ ๊ฒ์ ๋์๋๋ ํ์ด์ง ๊ตฌ์กฐ์ฒด๋ ์์ง๋ง ์ฐ๊ฒฐ๋ ๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ ํ๋ ์์ ์์ง ์๊ณ , ํ์ด์ง์ ์ค์ ์ฝํ ์ธ ๋ ์์ง ๋ก๋๋์ง ์์์ ์๋ฏธํ๋ค.
ํ์ด์ง ํดํธ๋ก ์ธํด ์ค์ ๋ก ์ฝํ ์ธ ๊ฐ ํ์ํ ๋ ๋ก๋๋๋ค. (ํ์ด์ง ํดํธ๋ก ์๊ทธ๋์ ๋ฐ์)
์ธ ๊ฐ์ง ํ์ด์ง ํ์ (VM_UNINIT, VM_ANON, VM_FILE)์ ๊ฐ์ง๋๋ฐ ๊ฐ ํ์ด์ง๋ณ๋ก ์ด๊ธฐํ ๋ฃจํด์ด ๋ค๋ฅด๋ค.
ํ์ด์ง ํดํธ ์ฒ๋ฆฌ ์ ์ฐจ ์ค์ uninit_initialize ์ ํธ์ถํ๊ณ ์ด์ ์ ์ค์ ํ ์ด๊ธฐํ ํจ์๋ฅผ ํธ์ถํ๋ค.
ํ์ด์ง๋ ์ด๊ธฐํโ(ํ์ด์ง ํดํธ โ ์ง์ฐ ๋ก๋ฉ โ ์ค์ ์ธ โ ์ค์ ์์ โ โฆ) โ ์ญ์ ๋ผ๋ cycle์ ๊ฐ์ง๋ค.
ํ์ด์ง ํ์ (ํน์ VM_TYPE)๋ณ ์ด๊ธฐํ ๋ฐฉ๋ฒ์ด ๋ค๋ฅธ ๊ฒ์ฒ๋ผ, cycle์ ์ ํ๋ง๋ค ํ์ด์ง ํ์ ๋ณ๋ก ๋ค๋ฅธ ํ๋ก์์ ๊ฐ ์๊ตฌ๋จ
๐ก ๊ฐ ํ์ด์ง ํ์ ์ ๋ฐ๋ฅธ ์ ํ(transition processes) ๊ณผ์ ์ ๊ตฌํํด์ผํ๋ค.
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;
/* Check wheter the upage is already occupied or not. */
if (spt_find_page (spt, upage) == NULL) {
/** #project3-Anonymous Page */
struct page *page = malloc(sizeof(struct page));
if (!page)
goto err;
typedef bool (*initializer_by_type)(struct page *, enum vm_type, void *);
initializer_by_type initializer = NULL;
switch (VM_TYPE(type))
{
case VM_ANON:
initializer = anon_initializer;
break;
case VM_FILE:
initializer = file_backed_initializer;
break;
}
uninit_new(page, upage, init, type, aux, initializer);
page->writable = writable;
return spt_insert_page(spt, page);
}
err:
return false;
}
/** Project 3-Memory Mapped Files */
struct vm_load_arg
{
struct file *file;
off_t ofs;
uint32_t read_bytes;
uint32_t zero_bytes;
};
static bool
load_segment (struct file *file, off_t ofs, uint8_t *upage,
uint32_t read_bytes, uint32_t zero_bytes, bool writable) {
ASSERT ((read_bytes + zero_bytes) % PGSIZE == 0);
ASSERT (pg_ofs (upage) == 0);
ASSERT (ofs % PGSIZE == 0);
file_seek (file, ofs);
while (read_bytes > 0 || zero_bytes > 0) {
/* Do calculate how to fill this page.
* We will read PAGE_READ_BYTES bytes from FILE
* and zero the final PAGE_ZERO_BYTES bytes. */
size_t page_read_bytes = read_bytes < PGSIZE ? read_bytes : PGSIZE;
size_t page_zero_bytes = PGSIZE - page_read_bytes;
/* Get a page of memory. */
uint8_t *kpage = palloc_get_page (PAL_USER);
if (kpage == NULL)
return false;
/* Load this page. */
if (file_read (file, kpage, page_read_bytes) != (int) page_read_bytes) {
palloc_free_page (kpage);
return false;
}
memset (kpage + page_read_bytes, 0, page_zero_bytes);
/* Add the page to the process's address space. */
if (!install_page (upage, kpage, writable)) {
printf("fail\n");
palloc_free_page (kpage);
return false;
}
/* Advance. */
read_bytes -= page_read_bytes;
zero_bytes -= page_zero_bytes;
upage += PGSIZE;
}
return true;
}
static bool
lazy_load_segment (struct page *page, void *aux) {
/** Project 3-Anonymous Page */
struct vm_load_arg *aux_p = aux;
struct file *file = aux_p->file;
off_t offset = aux_p->ofs;
size_t page_read_bytes = aux_p->read_bytes;
size_t page_zero_bytes = PGSIZE - page_read_bytes;
file_seek(file, offset);
if (file_read(file, page->frame->kva, page_read_bytes) != (off_t)page_read_bytes) {
palloc_free_page(page->frame->kva);
return false;
}
memset(page->frame->kva + page_read_bytes, 0, page_zero_bytes);
return true;
}
#ifdef VM
/* Table for whole virtual memory owned by thread. */
struct supplemental_page_table spt;
/** Project 3-Anonymous Page - stack์ฉ ํฌ์ธํฐ ์์ฑ*/
void *stack_bottom;
void *stack_pointer;
#endif
static bool
setup_stack (struct intr_frame *if_) {
bool success = false;
void *stack_bottom = (void *) (((uint8_t *) USER_STACK) - PGSIZE);
/** Project 3-Anonymous Page */
if (vm_alloc_page(VM_ANON | VM_MARKER_0, stack_bottom, 1)) { // MARKER_0๋ก STACK์ ์๋ ๊ฒ์ ํ์
success = vm_claim_page(stack_bottom);
if (success) {
if_->rsp = USER_STACK;
thread_current()->stack_bottom = stack_bottom;
}
}
return success;
}
bool
vm_try_handle_fault (struct intr_frame *f UNUSED, void *addr UNUSED,
bool user UNUSED, bool write UNUSED, bool not_present UNUSED) {
struct supplemental_page_table *spt UNUSED = &thread_current ()->spt;
/** Project 3-Anonymous Page */
struct page *page = spt_find_page(&thread_current()->spt, addr);
if (addr == NULL || is_kernel_vaddr(addr))
return false;
if (not_present)
{
page = spt_find_page(spt, addr);
if (page == NULL)
return false;
if (write == 1 && page->writable == 0)
return false;
return vm_do_claim_page(page);
}
return false;
}
bool
supplemental_page_table_copy (struct supplemental_page_table *dst UNUSED,
struct supplemental_page_table *src UNUSED) {
/** Project 3-Anonymous Page */
struct hash_iterator i;
hash_first(&i, &src->spt_hash);
while (hash_next(&i))
{
struct page *src_page = hash_entry(hash_cur(&i), struct page, hash_elem);
enum vm_type src_type = src_page->operations->type;
if (src_type == VM_UNINIT)
{
vm_alloc_page_with_initializer(
src_page->uninit.type,
src_page->va,
src_page->writable,
src_page->uninit.init,
src_page->uninit.aux);
}
else
{
if (vm_alloc_page(src_type, src_page->va, src_page->writable) && vm_claim_page(src_page->va))
{
struct page *dst_page = spt_find_page(dst, src_page->va);
memcpy(dst_page->frame->kva, src_page->frame->kva, PGSIZE);
}
}
}
return true;
}
/** Project 3-Anonymous Page */
uint64_t page_hash(const struct hash_elem *e, void *aux);
bool page_less(const struct hash_elem *a, const struct hash_elem *b, void *aux);
void hash_page_destroy(struct hash_elem *e, void *aux);
#endif /* VM_VM_H */
/** Project 3-Anonymous Page */
void
hash_page_destroy(struct hash_elem *e, void *aux)
{
struct page *page = hash_entry(e, struct page, hash_elem);
destroy(page);
free(page);
}
void
supplemental_page_table_kill (struct supplemental_page_table *spt UNUSED) {
/** Project 3-Anonymous Page */
hash_clear(&spt->spt_hash, hash_page_destroy);
}
#ifndef VM
/** project2-System Call */
void check_address(void *addr) {
thread_t *curr = thread_current();
if (is_kernel_vaddr(addr) || addr == NULL || pml4_get_page(curr->pml4, addr) == NULL)
exit(-1);
}
#else
/** Project 3-Anonymous Page */
struct page *check_address(void *addr) {
struct thread *curr = thread_current();
if (is_kernel_vaddr(addr) || addr == NULL || !spt_find_page(&curr->spt, addr))
exit(-1);
return spt_find_page(&curr->spt, addr);
}
#endif
/** Project 3-Anonymous Page */
#ifndef VM
void check_address(void *addr);
#else
/** #Project 3: Anonymous Page */
struct page *check_address(void *addr);
#endif
/** Project 3-Anonymous Page */
if ((!not_present && write) || (fault_addr < 0x400000 || fault_addr >= USER_STACK))
{
exit(-1);
}
pass tests/userprog/args-none
pass tests/userprog/args-single
pass tests/userprog/args-multiple
pass tests/userprog/args-many
pass tests/userprog/args-dbl-space
pass tests/userprog/halt
pass tests/userprog/exit
pass tests/userprog/create-normal
pass tests/userprog/create-empty
pass tests/userprog/create-null
pass tests/userprog/create-bad-ptr
pass tests/userprog/create-long
pass tests/userprog/create-exists
pass tests/userprog/create-bound
pass tests/userprog/open-normal
pass tests/userprog/open-missing
pass tests/userprog/open-boundary
pass tests/userprog/open-empty
pass tests/userprog/open-null
pass tests/userprog/open-bad-ptr
pass tests/userprog/open-twice
pass tests/userprog/close-normal
pass tests/userprog/close-twice
pass tests/userprog/close-bad-fd
pass tests/userprog/read-normal
pass tests/userprog/read-bad-ptr
pass tests/userprog/read-boundary
pass tests/userprog/read-zero
pass tests/userprog/read-stdout
pass tests/userprog/read-bad-fd
pass tests/userprog/write-normal
pass tests/userprog/write-bad-ptr
pass tests/userprog/write-boundary
pass tests/userprog/write-zero
pass tests/userprog/write-stdin
pass tests/userprog/write-bad-fd
pass tests/userprog/fork-once
pass tests/userprog/fork-multiple
pass tests/userprog/fork-recursive
pass tests/userprog/fork-read
pass tests/userprog/fork-close
pass tests/userprog/fork-boundary
pass tests/userprog/exec-once
pass tests/userprog/exec-arg
pass tests/userprog/exec-boundary
pass tests/userprog/exec-missing
pass tests/userprog/exec-bad-ptr
pass tests/userprog/exec-read
pass tests/userprog/wait-simple
pass tests/userprog/wait-twice
pass tests/userprog/wait-killed
pass tests/userprog/wait-bad-pid
pass tests/userprog/multi-recurse
pass tests/userprog/multi-child-fd
pass tests/userprog/rox-simple
pass tests/userprog/rox-child
pass tests/userprog/rox-multichild
pass tests/userprog/bad-read
pass tests/userprog/bad-write
pass tests/userprog/bad-read2
pass tests/userprog/bad-write2
pass tests/userprog/bad-jump
pass tests/userprog/bad-jump2
FAIL tests/vm/pt-grow-stack
pass tests/vm/pt-grow-bad
FAIL tests/vm/pt-big-stk-obj
pass tests/vm/pt-bad-addr
pass tests/vm/pt-bad-read
pass tests/vm/pt-write-code
FAIL tests/vm/pt-write-code2
FAIL tests/vm/pt-grow-stk-sc
pass tests/vm/page-linear
pass tests/vm/page-parallel
pass tests/vm/page-merge-seq
FAIL tests/vm/page-merge-par
FAIL tests/vm/page-merge-stk
FAIL tests/vm/page-merge-mm
pass tests/vm/page-shuffle
FAIL tests/vm/mmap-read
FAIL tests/vm/mmap-close
FAIL tests/vm/mmap-unmap
FAIL tests/vm/mmap-overlap
FAIL tests/vm/mmap-twice
FAIL tests/vm/mmap-write
FAIL tests/vm/mmap-ro
FAIL tests/vm/mmap-exit
FAIL tests/vm/mmap-shuffle
pass tests/vm/mmap-bad-fd
FAIL tests/vm/mmap-clean
FAIL tests/vm/mmap-inherit
FAIL tests/vm/mmap-misalign
FAIL tests/vm/mmap-null
FAIL tests/vm/mmap-over-code
FAIL tests/vm/mmap-over-data
FAIL tests/vm/mmap-over-stk
FAIL tests/vm/mmap-remove
pass tests/vm/mmap-zero
pass tests/vm/mmap-bad-fd2
pass tests/vm/mmap-bad-fd3
pass tests/vm/mmap-zero-len
FAIL tests/vm/mmap-off
FAIL tests/vm/mmap-bad-off
FAIL tests/vm/mmap-kernel
FAIL tests/vm/lazy-file
pass tests/vm/lazy-anon
FAIL tests/vm/swap-file
FAIL tests/vm/swap-anon
FAIL tests/vm/swap-iter
FAIL tests/vm/swap-fork
pass tests/filesys/base/lg-create
pass tests/filesys/base/lg-full
pass tests/filesys/base/lg-random
pass tests/filesys/base/lg-seq-block
pass tests/filesys/base/lg-seq-random
pass tests/filesys/base/sm-create
pass tests/filesys/base/sm-full
pass tests/filesys/base/sm-random
pass tests/filesys/base/sm-seq-block
pass tests/filesys/base/sm-seq-random
pass tests/filesys/base/syn-read
pass tests/filesys/base/syn-remove
pass tests/filesys/base/syn-write
pass tests/threads/alarm-single
pass tests/threads/alarm-multiple
pass tests/threads/alarm-simultaneous
pass tests/threads/alarm-priority
pass tests/threads/alarm-zero
pass tests/threads/alarm-negative
pass tests/threads/priority-change
pass tests/threads/priority-donate-one
pass tests/threads/priority-donate-multiple
pass tests/threads/priority-donate-multiple2
pass tests/threads/priority-donate-nest
pass tests/threads/priority-donate-sema
pass tests/threads/priority-donate-lower
pass tests/threads/priority-fifo
pass tests/threads/priority-preempt
pass tests/threads/priority-sema
pass tests/threads/priority-condvar
pass tests/threads/priority-donate-chain
FAIL tests/vm/cow/cow-simple
33 of 141 tests failed.