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

ํํ ์ค์์์ ๋์๊ฐ๋ ํ๋ก์ธ์ค์ ์ฃผ์ ๊ณต๊ฐ์ ๋์ํ ํ๋ฉด ์์ ๊ฐ๋ค.
๊ทธ๋ฆผ์ ์์ธํ๋ณด๋ฉด Disk ์์ญ๊ณผ ๋งคํ๋๋ ํ๋(text), ์ด๋ก์ ์์ญ(Data)์ด ์๊ณ ,
Disk ์์ญ๊ณผ ์๋ฌด๋ฐ ๊ด๋ จ์ด ์๋ ๋นจ๊ฐ(Stack), ์ฃผํฉ(BSS) ์์ญ์ด ์๋ค.
๊ฒฐ๋ก ๋ถํฐ ๋งํ์๋ฉด Stack, BSS ์์ญ๊ณผ ๋งคํ๋ ๋นจ๊ฐ, ์ฃผํฉ์ ํ์ด์ง๊ฐ ๋ฐ๋ก Anonymous Page.
์ฆ ์ง์ ๋ ํ์ผ ์์ค๊ฐ ์๊ธฐ ๋๋ฌธ์ ์ต๋ช
์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค.
์คํ๊ณผ ํ ๊ณผ ๊ฐ์ ์คํํ์ผ์ ์ฌ์ฉ๋๋ฉฐ, ํ์ํ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ๋์ ์ผ๋ก ํ ๋นํ์ฌ ํ๋ก๊ทธ๋จ์ ์๊ตฌ์ฌํญ์ ๋ง๊ฒ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ์ฉํ ์ ์๋ค.
ํ๋ก์ ํธ 3์์ ๋ง์ฃผํ๋ ์ฒซ๋ฒ์งธ ์ฅ์ ๋ฌผ์ Lazy Loading์ด๋ค.
์ด๊ฑธ ๊ตฌํํ๊ธฐ ์ํด ์ด์ ์ SPT์ Frame ๊ด๋ฆฌ ํจ์๋ฅผ ๊ตฌํํ๋ค.
Lazy Loading์ ๋ชฉ์ ์ ์คํํ์ผ์ ๋ก๋ํ ๋ ๋ถํ์ํ ๋์คํฌ ์ ๊ทผ์ ์ค์ด๊ธฐ ์ํด ๊ตฌํํ๋ ๊ฒ.
๋ง์ฝ ํ์ผ ๊ธฐ๋ฐ ํ์ด์ง๋ผ๋ฉด, ๋ฌผ๋ฆฌ ํ๋ ์ ํ ๋น -> ๋์คํฌ์์ ํ์ผ ์ฝ๊ธฐ(I/O)
์ ์์
์์๋ฅผ,
์ต๋ช
ํ์ด์ง๋ผ๋ฉด, ๋ฌผ๋ฆฌ ํ๋ ์ ํ ๋น -> ํด๋นํ๋ ์ 0์ผ๋ก ์ฑ์ฐ๊ธฐ(CPU์ฐ์ฐ)
๋์คํฌ I/O๋ ์๊ณ , ๋น์ฉ์ด ๋ง์ด ๋๋ ์์
์ ์ค์ ์ฌ์ฉ ๋๋ ์๊ฐ์ผ๋ก ๋ฏธ๋ฃฌ๋ค.
BSS segment๋ ์ด๊ธฐํ๋์ง ์์(uninitialized) ์ ์ญ/์ ์ ๋ณ์๋ฅผ ์ํ ์์ญ์ด๋ค.
ํ๋ก๊ธ๋จ ์์์ ๋ชจ๋ ๋ด์ฉ์ด 0์ด์ด์ผ ํ๋ค.
์ง์ฐ ๋ก๋ฉ์ด ์๋ค๋ฉด ํ๋ก๊ทธ๋จ ์์์ ์ปค๋, ๋ฌผ๋ฆฌ ํ๋ ์์ ๋ชจ๋ ํ ๋นํ๊ณ memset์ ์ด์ฉํด์ 0์ผ๋ก ์ฑ์์ฃผ์ด์ผ ํจ.
๋ฐ๋ฉด ์ง์ฐ๋ก๋ฉ์ด ์๋ค๋ฉด,
ํ๋ก๊ทธ๋จ ์์์ ์ปค๋์ ๋ฉ๋ชจ๋ฆฌ์ ์๋ฌด๋ฐ ์์
์ ํ์ง ์๊ณ ,
SPT์ ์ด VA๋ ๋์ค์ ์ ๊ทผ์ด ์ผ์ด๋๋ฉด 0์ผ๋ก ์ฑ์์ง Anonymous Page ๊ฐ ๋์ด์ผ ํ๋ค๊ณ ์ฝ์๋ง ๊ธฐ๋กํด๋ .
userprog/exception.c์ page_fault() โ vm/vm.c์ vm_try_handle_fault() ๋ก ์ ์ด ์ด๋vm_try_handle_fault() โ ์ด ํดํธ๊ฐ ์ ํจํ ํ์ด์ง fault(์ง์ฐ๋ก๋ฉ, ์ค์ ์ธ)์ธ์ง ํ์ธ์ง์ฐ ๋ก๋ฉ ํ์ด์ง Fault ์ ์ฒ๋ฆฌ ๊ณผ์
vm_alloc_page_with_initializer ํจ์์์ ์ด์ ์ ์ค์ ํด๋ ํน์ ์ด๊ธฐํ ํจ์ ํธ์ถlazy_load_segment ํจ์๋ฅผ ๊ตฌํํด์ผํจ โ ํน์ ์ธ๊ทธ๋จผํธ๋ฅผ ์ค์ ๋ก ๋ก๋ฉํ๋ ์ญํ ๋ด๋นAnonymous Page Flow

/* ํ์ด์ง ๊ตฌ์กฐ์ฒด๋ฅผ ์์ฑํ๊ณ ์ ์ ํ ์ด๊ธฐํ ํจ์๋ฅผ ์ค์ */
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)
{
/* TODO: Create the page, fetch the initialier according to the VM type,
* TODO: and then create "uninit" page struct by calling uninit_new. You
* TODO: should modify the field after calling the uninit_new. */
/* TODO: Insert the page into the spt. */
// 1. ํ์ด์ง ์์ฑ
struct page *p = (struct page *)malloc(sizeof(struct page));
// 2. ํ์
์ ๋ฐ๋ฅธ ์ด๊ธฐํ ํจ์ ๊ฐ์ ธ์ค๊ธฐ
bool (*page_initializer)(struct page *, enum vm_type, void *);
switch (VM_TYPE(type))
{
case VM_ANON:
page_initializer = anon_initializer;
break;
case VM_FILE:
page_initializer = file_backed_initializer;
break;
}
// 3. uninit ํ์
์ ํ์ด์ง๋ก ์ด๊ธฐํ
// uninit_new -> uninit ํ์
์ผ๋ก ์ด๊ธฐํํด์ฃผ๋ ํจ์
uninit_new(p, upage, init, type, aux, page_initializer);
// 4. ํ๋ ์์
p->writable = writable;
// 5. ํ์ด์ง spt ์ถ๊ฐ
return spt_insert_page(spt, p);
}
err:
return false;
}
VM_UNINIT ํ์ด์ง์ ์ฒซ๋ฒ์งธ ํ์ด์ง ํดํธ ๋ฐ์์ ์ด ํจ์๊ฐ ํธ์ถ.
ํ์ด์ง๋ฅผ ์ค์ ์ฌ์ฉ ๊ฐ๋ฅ ์ํ๋ก ๋ฐ๊พธ๋ ์ญํ ์ ์ํํ๋ค.
/* Initalize the page on first fault */
static bool
uninit_initialize(struct page *page, void *kva)
{
struct uninit_page *uninit = &page->uninit;
/* Fetch first, page_initialize may overwrite the values */
vm_initializer *init = uninit->init; // lazy_load_segment
void *aux = uninit->aux; // lazy_load_arg
/* TODO: You may need to fix this function. */
return uninit->page_initializer(page, uninit->type, kva) &&
(init ? init(page, aux) : true);
}
์ ์ฌ์ง์ AUX๋ก ๋ฌถ์ด๋์ ์ ์ ๋ณด๋ฅผ ๋ค ๋๊ฒจ์ฃผ๋ฉด ๋๋ค.
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); // read_bytes + zero_bytes๊ฐ ํ์ด์ง ํฌ๊ธฐ(PGSIZE)์ ๋ฐฐ์์ธ์ง ํ์ธ
ASSERT(pg_ofs(upage) == 0); // upage๊ฐ ํ์ด์ง ์ ๋ ฌ๋์ด ์๋์ง ํ์ธ
ASSERT(ofs % PGSIZE == 0) // ofs๊ฐ ํ์ด์ง ์ ๋ ฌ๋์ด ์๋์ง ํ์ธ;
while (read_bytes > 0 || zero_bytes > 0) // read_bytes์ 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; // ์ต๋๋ก ์ฝ์ ์ ์๋ ํฌ๊ธฐ๋ PGSIZE
size_t page_zero_bytes = PGSIZE - page_read_bytes;
/* TODO: Set up aux to pass information to the lazy_load_segment. */
// loading์ ์ํด ํ์ํ ์ ๋ณด๋ฅผ ํฌํจํ๋ ๊ตฌ์กฐ์ฒด๋ฅผ ๋ง๋ค์ด์ผ ํฉ๋๋ค.
struct lazy_load_arg *lazy_load_arg = (struct lazy_load_arg *)malloc(sizeof(struct lazy_load_arg));
lazy_load_arg->file = file; // ๋ด์ฉ์ด ๋ด๊ธด ํ์ผ ๊ฐ์ฒด
lazy_load_arg->ofs = ofs; // ์ด ํ์ด์ง์์ ์ฝ๊ธฐ ์์ํ ์์น
lazy_load_arg->read_bytes = page_read_bytes; // ์ด ํ์ด์ง์์ ์ฝ์ด์ผ ํ๋ ๋ฐ์ดํธ ์
lazy_load_arg->zero_bytes = page_zero_bytes; // ์ด ํ์ด์ง์์ read_bytes๋งํผ ์ฝ๊ณ ๊ณต๊ฐ์ด ๋จ์ 0์ผ๋ก ์ฑ์์ผ ํ๋ ๋ฐ์ดํธ ์
// vm_alloc_page_with_initializer๋ฅผ ํธ์ถํ์ฌ ๋๊ธฐ ์ค์ธ ๊ฐ์ฒด๋ฅผ ์์ฑํฉ๋๋ค.
if (!vm_alloc_page_with_initializer(VM_ANON, upage, writable, lazy_load_segment, lazy_load_arg))
return false;
/* Advance. */
// ๋ค์ ๋ฐ๋ณต์ ์ํ์ฌ ์ฝ์ด๋ค์ธ ๋งํผ ๊ฐ์ ๊ฐฑ์ ํฉ๋๋ค.
read_bytes -= page_read_bytes;
zero_bytes -= page_zero_bytes;
upage += PGSIZE;
ofs += page_read_bytes;
}
return true;
}
bool lazy_load_segment(struct page *page, void *aux)
{
/* TODO: Load the segment from the file */
/* TODO: This called when the first page fault occurs on address VA. */
/* TODO: VA is available when calling this function. */
struct lazy_load_arg *lazy_load_arg = (struct lazy_load_arg *)aux;
// 1) ํ์ผ์ position์ ofs์ผ๋ก ์ง์ ํ๋ค.
file_seek(lazy_load_arg->file, lazy_load_arg->ofs);
// 2) ํ์ผ์ read_bytes๋งํผ ๋ฌผ๋ฆฌ ํ๋ ์์ ์ฝ์ด ๋ค์ธ๋ค.
if (file_read(lazy_load_arg->file, page->frame->kva, lazy_load_arg->read_bytes) != (int)(lazy_load_arg->read_bytes))
{
palloc_free_page(page->frame->kva);
return false;
}
// 3) ๋ค ์ฝ์ ์ง์ ๋ถํฐ zero_bytes๋งํผ 0์ผ๋ก ์ฑ์ด๋ค.
memset(page->frame->kva + lazy_load_arg->read_bytes, 0, lazy_load_arg->zero_bytes);
return true;
}
๋ง์ง๋ง์ผ๋ก ํ์ด์ง ํด๋ ๋ฐ์์ ํธ๋ค๋ฌ ํจ์๋ฅผ ์์ ํ๋ค.
/* Return true on 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;
struct page *page = NULL;
if (addr == NULL)
return false;
if (is_kernel_vaddr(addr))
return false;
if (not_present) // ์ ๊ทผํ ๋ฉ๋ชจ๋ฆฌ์ physical page๊ฐ ์กด์ฌํ์ง ์์ ๊ฒฝ์ฐ
{
/* TODO: Validate the fault */
// ํ์ด์ง ํดํธ๊ฐ ์คํ ํ์ฅ์ ๋ํ ์ ํจํ ๊ฒฝ์ฐ์ธ์ง๋ฅผ ํ์ธํ๋ค.
void *rsp = f->rsp; // user access์ธ ๊ฒฝ์ฐ rsp๋ ์ ์ stack์ ๊ฐ๋ฆฌํจ๋ค.
if (!user) // kernel access์ธ ๊ฒฝ์ฐ thread์์ rsp๋ฅผ ๊ฐ์ ธ์์ผ ํ๋ค.
rsp = thread_current()->rsp;
page = spt_find_page(spt, addr);
if (page == NULL)
return false;
if (write == 1 && page->writable == 0) // write ๋ถ๊ฐ๋ฅํ ํ์ด์ง์ write ์์ฒญํ ๊ฒฝ์ฐ
return false;
return vm_do_claim_page(page);
}
return fals