https://casys-kaist.github.io/pintos-kaist/project3/introduction.html
https://oslab.kaist.ac.kr/pintosslides/


Page Fault ๋ฐ์ -> vm_try_fault_hander -> uninit_initialize -> lazy_load_segment -> pml4_set_page์ด๊ฑธ ์ข๋ ์ฝ๊ฒ ๊ทธ๋ฆผ์ผ๋ก ๊ทธ๋ ค๋ณด๋ฉด

์๋๋ผ๋ฉด kill ํ๋ ๊ฒ์
1. ์ฒซ๋ฒ์งธ Page Fault ๊ฐ ๋ฐ์
2. SPT(Supplement_page_table)์ ํ์ํ์ฌ ๋ฉ๋ชจ๋ฆฌ์ ์ฌ๋ผ๊ฐ ๋ฐ์ดํฐ๊ฐ ์๋์ง๋ฅผ ํ์
3. Demand Paging
๋ฐ๋ผ์ ์ ๊ทธ๋ฆผ์ฒ๋ผ SPT ๊ตฌํ -> Frame ๊ด๋ฆฌ -> Anonymous Page & lazy loading์ผ๋ก ์งํํ๋ค.
//vm.h
/* 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 spt_pages;
};
supplemental_page_table ๊ตฌ์กฐ์ฒด์ ํด์ ์๋ฃ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ์ฌ SPT๋ฅผ ์ ์ํ๋ค.

Key๋ VA๊ฐ ๋ ๊ฒ์ด๊ณ , Value๋ hash_elem์ด ๋ ๊ฒ.
๊ทธ๋ผ ์ด hash_elem์ ์ด๋๋ค๊ฐ ์ ์ธํ๋๋ฉด Page ๊ตฌ์กฐ์ฒด์ ์ ์ธํ๋ค.
// vm.h
/* The representation of "page".
* This is kind of "parent class", which has four "child class"es, which are
* 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 */
/* Hash ์๋ฃ๊ตฌ์กฐ ํ์ฉ ์ํ ๋ฉค๋ฒ๋ณ์ ์ถ๊ฐ */
struct hash_elem hash_elem; /* Hash table element. */
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;
#endif
};
};
ํด์ ์๋ฃ๊ตฌ์กฐ์ด๊ธฐ ๋๋ฌธ์ GitBook์ APPENDIX์ HASH FUNCTION ๋ถ๋ถ์ ์ฐธ๊ณ ํ๋ค.
/* Returns a hash value for page p. */
unsigned
page_hash(const struct hash_elem *p_, void *aux UNUSED)
{
const struct page *p = hash_entry(p_, struct page, hash_elem);
return hash_bytes(&p->va, sizeof p->va);
}
/* Returns true if page a precedes page b. */
bool page_less(const struct hash_elem *a_,
const struct hash_elem *b_, void *aux UNUSED)
{
const struct page *a = hash_entry(a_, struct page, hash_elem);
const struct page *b = hash_entry(b_, struct page, hash_elem);
return a->va < b->va;
}
/* Initialize new supplemental page table */
void supplemental_page_table_init(struct supplemental_page_table *spt UNUSED)
{
// ์ธ์๋ก ๋ฐ์ spt์ pages ํด์ ํ
์ด๋ธ์ ์ด๊ธฐํ
hash_init(spt, page_hash, page_less, NULL);
}
hash_initํจ์๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํ ํฌํผ ํจ์๋ฅผ ๋๊ฐ ์ ์ธํด์ฃผ๊ณ ,
SPT์ ์ด๊ธฐํ๋ฅผ ๋ด๋นํ๋ supplemental_page_table_init ํจ์์ ํ์ฉํ์๋ค.
spt_find_page
spt์์ ์ธ์๋ก ๋ค์ด์ค๋ VA์ ํด๋นํ๋ ํ์ด์ง๋ฅผ ํด์ ์๋ฃ๊ตฌ์กฐ์ธ SPT์์ ์ฐพ๋ ํจ์.
hash_find๋ฅผ ์ฌ์ฉํ๊ณ , ํค๋ก ํ์ฉํ ์์ ํ์ด์ง๋ฅผ ์ ์ธํ์๋ค.
์ด๋ pg_round_down๋ฅผ ์ฌ์ฉํด์ ์ ๋ ฌํด์ ์ฝ์ด์ฃผ๋ ๊ฒ์ด ์ค์ํ๋ค.
spt_insert_page
์ฒ์์ ๋ฐ๋ก ์ ํจ์ฑ ๊ฒ์ฌ๊ฐ ํ์ํ์ค ์๊ณ spt_find_page๋ฅผ ํ๋๋ฐ, hash_insert์ ์ ํจ์ฑ ๊ฒ์ฌ ๋ก์ง์ด ์์ด ๊ทธ๋๋ก ๊ฐ์ ธ๋ค ์ผ๋ค.
/* Find VA from spt and return page. On error, return NULL. */
/*
์ฃผ์ด์ง spt์์ ์ฃผ์ด์ง va์ ํด๋นํ๋ struct page ์ ๋ณด๋ฅผ ํ์
*/
struct page *
spt_find_page(struct supplemental_page_table *spt UNUSED, void *va UNUSED)
{
// struct page *page = NULL;
struct page p_key;
// page = malloc(sizeof(struct page));
struct hash_elem *e;
// va์ ํด๋นํ๋ hash_elem ์ฐพ๊ธฐ
p_key.va = pg_round_down(va);
e = hash_find(&spt->spt_pages, &p_key.hash_elem);
// ์์ผ๋ฉด e์ ํด๋นํ๋ ํ์ด์ง ๋ฐํ
return e != NULL ? hash_entry(e, struct page, hash_elem) : NULL;
}
/* Insert PAGE into spt with validation. */
bool spt_insert_page(struct supplemental_page_table *spt UNUSED,
struct page *page UNUSED)
{
/* TODO: Fill this function. */
return hash_insert(&spt->spt_pages, &page->hash_elem) == NULL ? true : false; // ์กด์ฌํ์ง ์์ ๊ฒฝ์ฐ์๋ง ์ฝ์
}
/* The representation of "frame" */
struct frame {
void *kva;
struct page *page;
};
ํ์ฌ ์ด ํ๋ ์์ ๋ค์ด๊ฐ์๋ page์ ํฌ์ธํฐ๊ฐ ์์ด์ ์๋ก ์ฐธ์กฐ์ ์ญ์ฐธ์กฐ๊ฐ ๊ฐ๋ฅํ๋ค.
์ด๋ฐ ์์ผ๋ก ๊ตฌ์ฑ๋์ด์๋ค๊ณ ๋ณด๋ฉด ๋๋ค.
๋ง์ฝ malloc์ผ๋ก ์ด๊ธฐํํ๋ค๋ฉด ์ฐ๋ ๊ธฐ๊ฐ์ด ๋ค์ด๊ฐ ์ ์๋ค.
frame->page = 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.*/
/* ์ฌ์ฉ์ ํ์์ ์๋ก์ด ๋ฌผ๋ฆฌ ํ๋ ์ ๊ฐ์ ธ์ค๊ธฐ.
* ํ์ด์ง ๊ต์ฒด ๋ก์ง ์ถ๊ฐ ์ ๊น์ง๋ ์คํจ ์ PANIC. */
static struct frame *
vm_get_frame(void)
{
struct frame *frame = NULL;
/* TODO: Fill this function. */
void *kva = palloc_get_page(PAL_USER); // user pool์์ ์๋ก์ด physical page๋ฅผ ๊ฐ์ ธ์จ๋ค.
if (kva == NULL) // page ํ ๋น ์คํจ -> ๋์ค์ swap_out ์ฒ๋ฆฌ
PANIC("todo"); // OS๋ฅผ ์ค์ง์ํค๊ณ , ์์ค ํ์ผ๋ช
, ๋ผ์ธ ๋ฒํธ, ํจ์๋ช
๋ฑ์ ์ ๋ณด์ ํจ๊ป ์ฌ์ฉ์ ์ง์ ๋ฉ์์ง๋ฅผ ์ถ๋ ฅ
frame = calloc(1, sizeof(struct frame));
if (frame == NULL)
{ // malloc ์คํจ ์ฒ๋ฆฌ
palloc_free_page(kva); // ์ด๋ฏธ ํ ๋น๋ฐ์ kva๋ ๋ฐํ
PANIC("vm_get_frame: Malloc ํ ๋น ์คํจ");
}
frame->kva = kva; // ํ๋ ์ ๋ฉค๋ฒ ์ด๊ธฐํ
// frame->page = NULL; // ๋ช
์์ ์ด๊ธฐํ ์ถ๊ฐ
ASSERT(frame != NULL);
ASSERT(frame->page == NULL);
return frame;
}
์ฆ pml4์ ๊ฐ์ ํ์ด์ง์ ๋ฌผ๋ฆฌ ํ๋ ์์ ๋งคํ์ํค๋ ์์ ๊น์ง ์งํํ๋ค.
/* Claim the page that allocate on VA. */
// va๋ก page๋ฅผ ์ฐพ์์ vm_do_claim_page๋ฅผ ํธ์ถํ๋ ํจ์
static bool
vm_do_claim_page(struct page *page)
{
struct frame *frame = vm_get_frame();
/* Set links */
frame->page = page;
page->frame = frame;
/* TODO: Insert page table entry to map page's VA to frame's PA. */
// ๊ฐ์ ์ฃผ์์ ๋ฌผ๋ฆฌ ์ฃผ์๋ฅผ ๋งคํ
struct thread *current = thread_current();
pml4_set_page(current->pml4, page->va, frame->kva, page->writable);
return swap_in(page, frame->kva); // uninit_initialize
}
/* Claim the PAGE and set up the mmu. */
bool vm_claim_page(void *va UNUSED)
{
struct page *page = NULL;
/* TODO: Fill this function */
// spt์์ va์ ํด๋นํ๋ page ์ฐพ๊ธฐ
page = spt_find_page(&thread_current()->spt, va);
if (page == NULL)
return false;
return vm_do_claim_page(page);
}
๋ค์์ Anonymous Page ๊ตฌํ์ ์ ๋ฆฌํด๋ณด๊ฒ ๋ค...