Project3: Virtual Memory
01) Memory management
struct page
์๊ตฌ ํ์ด์ง (Demand Paging)์ ๊ตฌํํ๊ณ , ์ค์ ์ธ/์์์ ๊ด๋ฆฌํ๊ธฐ ์ํ ํ์ด์ง ๊ตฌ์กฐ์ฒด๊ฐ ๋ค์๊ณผ ๊ฐ์ด ์ ์ธ๋์ด ์๋ค. va
๋ ํ์ด์ง์ ์์ ์ฃผ์, ์ฆ ์ ์ ํ๋ก์ธ์ค์ ๊ฐ์์ฃผ์์ด๋ค. frame
์ ํ์ด์ง์ ๋งคํ๋ ๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์๋ ๊ตฌ์กฐ์ฒด๋ก, ๋งคํ ์ ๊น์ง๋ NULL
๋ก ์ ์ง๋๋ค.
struct page {
const struct page_operations *operations;
void *va; /* Address in terms of user space */
struct frame *frame; /* Back reference for frame */
union {
struct uninit_page uninit;
struct anon_page anon;
struct file_page file;
#ifdef EFILESYS
struct page_cache page_cache;
#endif
};
};
ํํ ์ค์ PRJ3์์๋ ํ์ด์ง๋ฅผ ์ธ ๊ฐ์ง ํ์
์ผ๋ก ๋๋๋๋ฐ, (page_cache
๋ฅผ ์ ์ธํ๊ณ ๋ณด์๋ฉด) uninit
, anon
, file
์ด๋ค. anon์ ์คํ/ํ๊ณผ ๊ฐ์ anonymous ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๋งํ๋ค. file์ mmap์ ํตํด ํ์ผ๊ณผ ๋งคํ๋ ๋ฉ๋ชจ๋ฆฌ, ๋๋ ์ด๊ธฐ์ lazy_load_segment
ํจ์๋ฅผ ํตํด ์ฌ๋ฆฐ .text, .data ์ธ๊ทธ๋จผํธ์ ๊ฐ์ file_backed_memory
๋ฅผ ๋งํ๋ค. uninit
์ ๊ฐ์์ฃผ์์ ๋ฉ๋ชจ๋ฆฌ ์์ญ์ด ์์ฝ๋์ด ์์ง๋ง, ์ค์ ๋ก ๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ์ ๋งคํ๋์ง ์์ ์ํ๋ฅผ ์๋ฏธํ๋ค. ๋ฐ๋ผ์, page fault๊ฐ ๋ฐ์ํ๋๋ฐ, ํด๋น ์ฃผ์๊ฐ uninit type์ ํ์ด์ง๋ผ๋ ๊ฒ์ ์ปค๋์ด ์๊ณ ์๋ค๋ฉด, (์ฆ, lazy load๊ฐ ํ์ํ ์ํฉ์์ ์๊ณ ์๋ค๋ฉด) ๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ์ ํด๋น ๊ฐ์์ฃผ์๋ฅผ ๋งคํํ์ฌ anon ๋๋ file type์ ๋ฉ๋ชจ๋ฆฌ๋ก ์ด๊ธฐํํด ์ค ์ ์๋ค.
page map level 4
/* The function table for page operations.
* This is one way of implementing "interface" in C.
* 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;
};
#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)
- operations: ๊ฐ ํ์ด์ง์ ๋์์ ์ ์ํ๋ค. ํฌ์ธํธ๋ ํ์ด์ง์ ํ์
์ด ๋ณํ ๋๋ง๋ค
swap_in
,swap_out
,destroy
ํ๋์ ํด๋น ํ์ ์ ์ฐ์ฐ์ ๊ตฌํํ ํจ์๋ฅผ ๋งคํํ๋ค๋ ์ ์ด๋ค. ์ด๋ฌํ ๋ฐฉ์์ ์ฌ์ฉํ๋ฉด, ํ์ด์ง์ ํ์ ์ ๊ด๊ณ์์ดswap_in
๋งคํฌ๋ก๋ฅผ ์ฌ์ฉํด ๊ฐ ํ์ด์ง๋ณ๋ก ๋ค๋ฅธ ๋ฃจํด์ ์คํ์ํฌ ์ ์๋ค. uninit type์swap_in
์ ์คํํ๋ฉด,anon_initializer
๊ฐ ์คํ๋๊ณ , ์ด ๋ operation ํ๋๋ฅผanon_operation
์ผ๋ก ๋ฐ๊พธ์ด ์ฃผ๋ ์์ด๋ค.
bool anon_initializer(struct page *page, enum vm_type type, void *kva) {
/* Set up the handler */
page->operations = &anon_ops;
struct anon_page *anon_page = &page->anon;
...
- union: ํ์ด์ง์ ํ์ ์ ๋ฐ๋ผ ๊ด๋ฆฌํด์ผ ํ ์ ๋ณด๊ฐ ๋ค๋ฅผ ์ ์๋ค. ์ด๋ฅผํ ๋ฉด, uninit type์ ํ์ด์ง๋, ๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ์ ๋งคํ๋ ๋ ์คํํด์ผ ํ ํจ์ (init, initializer ...) ํฌ์ธํฐ๋ฅผ ๊ฐ์ง๊ณ ์๋ค๊ฐ ๋งคํ๋ ์ดํ์ ํจ์๋ฅผ ์คํํจ์ผ๋ก์ lazy loadํ ์ ์๋ค. ๋ file_backed type์ ํ์ด์ง๋, ๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ์ ๋งคํ์ด ํด์ ๋ ๋ ๋ณ๊ฒฝ๋ ๋ด์ฉ์ ํ์ผ์ ๋ค์ ์จ ์ฃผ์ด์ผ ํ ์ ์์ผ๋ฏ๋ก ๋งคํ ์ ๋ณด๋ฅผ ๋ค๊ณ ์์ด์ผ ํ๋ค. ์ด๋ฌํ ์ ๋ณด๋ฅผ ๊ด๋ฆฌํด์ฃผ๊ธฐ ์ํด ๊ตฌ์กฐ์ฒด ์์ ํ๋๋ฅผ ๊ฐ๊ฐ ๋ค ๋ง๋ค ํ์ ์์ด, (ํ์ด์ง๋ ํ ๋ฒ์ ํ๋์ ์ํ๋ง ๊ฐ์ง๋ฏ๋ก) union์ ์ฌ์ฉํ๋ค. union์ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ๋ฉค๋ฒ๊ฐ ๊ณต์ ํ๋ ์๋ฃ๊ตฌ์กฐ์ธ๋ฐ, ๊ทธ ํฌ๊ธฐ๋ ๊ฐ์ฅ ํฐ ๋ฉค๋ฒ์ ํฌ๊ธฐ๋ก ๊ฒฐ์ ๋๋ค. ๋ฐ๋ผ์ ํ ๋ฒ์ ํ๋์ ๋ฉค๋ฒ ๋ณ์๋ง ์ฌ์ฉํ ์ ์๋ค. ๊ทธ๋์ ์ํ๋ณ ์ ๋ณด๋ฅผ ์ ์ฅํ๋๋ฐ ์ ์ฉํ ๊ฒ ๊ฐ๋ค.
)
Supplemetal Page Table
๋ค์ํ Page Fault ์๋๋ฆฌ์ค๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํด Supplemental Page Table์ ์ฌ์ฉํ๋ค. ์ด๋ฅผํ ๋ฉด, lazy loadํด์ผ ํ๋ ๊ฐ์์ฃผ์์ธ์ง๋ฅผ ํ์ธํ๊ธฐ ์ํด SPT๋ฅผ ํ์ธํด๋ณผ ์ ์๋ค. ๋, SPT ์์ page struct๋ฅผ ๋ณด๊ณ ์ด ํ์ด์ง๊ฐ ๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ์ ๋งคํ๋ ๋ ์ํ๋์ด์ผ ํ ์์ (ex. file read)์ ์คํํ ์ ์๋ค.
์ฐ๋ฆฌ ์กฐ๋ SPT๋ฅผ ํด์ ํ ์ด๋ธ๋ก ๊ตฌํํ๋ค. ํด์ ํ ์ด๋ธ์ key์ value๋ฅผ ๋งคํํ๋ ์๋ฃ๊ตฌ์กฐ์ด๋ค.
๐ Wikipedia ์ ๋ฆฌ
- associative array (์ฐ๊ด ๋ฐฐ์ด): CS๋ถ์ผ์์ associative array, map, symbol table, ๋๋ dictionary๋ ๊ฐ ํค๊ฐ ํด๋น ์งํฉ์์ ์ต์ ํ ๋ฒ ์ด์ ๋ฑ์ฅํ๋, ์ฌ๋ฌ ๊ฐ์ ํค-๊ฐ ์์ ์งํฉ์ผ๋ก ์ด๋ฃจ์ด์ง ์ถ์ ์๋ฃํ์ด๋ค. ์ํ์ ์ฉ์ด์์ associative array๋ ์ ํํ ์ ์์ญ์ ๊ฐ์ง ํจ์์ด๋ค. ์ผ๋ฐ์ ์ผ๋ก lookup, remove, insert ์ฐ์ฐ์ ์ง์ํ๋ค.
- dictionary problem: associative array๋ฅผ ๊ตฌํํ๋ ํจ์จ์ ์ธ ์๋ฃ๊ตฌ์กฐ๋ฅผ ์ค๊ณํ๋ ๊ณ ์ ์ ์ธ ๋ฌธ์ ์ด๋ค. ์ด ๋ฌธ์ ์ ํด๋ต์ผ๋ก ์ ์๋ ๊ฒ ์ค ์ฃผ์ํ ๋ ๊ฐ์ง๊ฐ ๋ฐ๋ก hash table๊ณผ search tree์ด๋ค.
- hash table: ํด์ ํ ์ด๋ธ์ ์ฐ๊ด ๋ฐฐ์ด์ ๊ตฌํํ๊ธฐ ์ํด hash function์ ์ฌ์ฉํด ์ธ๋ฑ์ค๋ฅผ ๊ณ์ฐํ๊ณ , ๊ฐ์ ํด๋น ์ธ๋ฑ์ค์ ๋ฒํท(๋๋ ์ฌ๋กฏ)์ ์ ์ฅํ๋ค. ์ ์ฅ๋ ๊ฐ์ ์ฐพ๊ธฐ ์ํด์๋ ๋ค์ hash function์ ์ฌ์ฉํด์ ์ธ๋ฑ์ค์ ์ ๊ทผํ๋ค. ์ด์์ ์ผ๋ก๋, ํ๋์ ํค๊ฐ ํ๋์ ๊ฐ์ผ๋ก ๋งคํ๋์ด์ผ ํ๊ธฐ์ ๊ฐ ๋ฒํท์ ์ ์ฅ๋๋ ๊ฐ์ ํ๋์ฌ์ผ ํ๋ค. ๊ทธ๋ฌ๊ธฐ ์ํด์, ๋ชจ๋ ํค์ ๋ํด ํด์ ํจ์์ ๋ฆฌํด๊ฐ์ด ์ ๋ํฌํด์ผ ํ๋ค. ํ์ง๋ง ๋๋ถ๋ถ์ ํด์ ํ ์ด๋ธ ๋์์ธ์ ์๋ฒฝํ์ง ์์ ํด์ ํจ์๋ฅผ ์ฌ์ฉํ๊ธฐ์, ๋ ์ด์์ ํค์ ๋ํด ๊ฐ์ index๋ฅผ ์์ฑํ๋ hash collision์ด ๋ฐ์ํ ์ ์๋ค.
pintos์ include/lib/kernel/hash.c
์์ ์ ๊ณตํ๋ ํด์ ํ
์ด๋ธ ์๋ฃ๊ตฌ์กฐ๋ ์ต์ด 4๊ฐ์ ๋ฒํท์ผ๋ก ํด์ ํ
์ด๋ธ์ด ์ด๊ธฐํ๋๊ณ , ์ด ๋ฒํท๋ค์ struct list
ํ์
์ ๊ฐ๋๋ค. ์ฆ, ๋ฒํท ํ๋์ ์ฌ๋ฌ ๊ฐ์ ๊ฐ์ด ์ ์ฅ๋ ์ ์๊ณ , list
์ ์ฌ์ฉ๋ฒ๊ณผ ๋์ผํ๊ฒ ์ ์ฅํ๊ณ ์ ํ๋ ๊ตฌ์กฐ์ฒด ์์ hash_elem
ํ๋๋ฅผ ์ถ๊ฐํจ์ผ๋ก์ ๊ตฌํํ ์ ์๋ค. ํ
์ด๋ธ์ ํ๋๊ฐ insert๋ ๋ ๋ง๋ค ํ์ํ ๋ฒํท์ ์๋ฅผ ์ฌ๊ณ์ฐํ์ฌ (๊ฐ ๋ฒํท ๋น BEST_ELEMS_PER_BUCKET๊ฐ๋ง ์ ์ฅํ๋๋ก) ์ฌ๋ฐฐ์นํ๋ rehash
ํจ์๋ฅผ ๋๋ฆฐ๋ค. ๋ฒํท์ด ๋์ด๋ ํ์๊ฐ ์๋ ๊ฒฝ์ฐ rehash
ํ์ง ์๋๋ค. ์ด๋ฌํ ๋ฐฉ๋ฒ์ ํตํด ํด์ ํ
์ด๋ธ์ lookup
, insert
, remove
๋ $O(1)$ ์๊ฐ๋ณต์ก๋๋ฅผ ๊ฐ๊ฒ ๋๋ค.
/* Returns the bucket in H that E belongs in. */
static struct list *find_bucket(struct hash *h, struct hash_elem *e) {
size_t bucket_idx = h->hash(e, h->aux) & (h->bucket_cnt - 1);
return &h->buckets[bucket_idx];
}
๐ ๋ฒํท์ ๊ฐ์๋ ์ 2์ ์ ๊ณฑ์์ผ๊น?
๋ฒํท์ 2์ ์ ๊ณฑ์๋ก ๋์ด๋๋๋ฐ, (4, 8, 16 , ...) ์ด๋ ํด์ ์ฝ๋๋ฅผ ํตํด ๋ฐ์ดํฐ๊ฐ ์ ์ฅ๋ ๋ฒํท์ ์ธ๋ฑ์ค๋ฅผ ๊ฒฐ์ ํ ๋ ์ฌ์ฉํ๋ ๋ชจ๋๋ฌ ์ฐ์ฐ์ ์ต์ ํํ๋ ๋ชฉ์ ์ผ๋ก ์ดํด๋ ์ ์๋ค. ๋ฒํท์ ์ฐพ๋ ์ ์ฝ๋๋ฅผ ๋ณด๋ฉด hash_code % bucket_count
๊ฐ ์๋๋ผ hash_code & (bucket_count - 1)
์ด๋ฐ ์์ผ๋ก ๋ชจ๋๋ฌ ์ฐ์ฐ์ ๊ตฌํํ๊ณ ์๋๋ฐ, ๋ง์ฝ ๋ฒํท์ ์๊ฐ 2์ ์ ๊ณฑ์๋ผ๋ฉด bucket_count - 1
์ ํจ์ผ๋ก์ ์ต์์ 1๋นํธ ์ดํ ๋นํธ๋ฅผ ๋ฐ์ ์ํฌ ์ ์๋ค. ์ด ๊ฐ์ AND ์ฐ์ฐ์ ์ทจํ๋ฉด ๋ค์๊ณผ ๊ฐ์ด ๋ชจ๋๋ฌ ์ฐ์ฐ๊ณผ ๋์ผํด์ง๊ฒ ๋๋ค. ๋นํธ ์ฐ์ฐ์ ๋ชจ๋๋ฌ ์ฐ์ฐ ๋๋น ๋น ๋ฅด๋ค. (์ด๊ฑฐ ๋ง๊ณ ๋ ๋ค๋ฅธ ์ด์ ๊ฐ ์์ ๊ฒ ๊ฐ๋ค. ์ฐพ์๋ณผ๊ฒ..)
hash_code = 13 // 1101
buck_cnt = 4 // 100
hash_code & (buck_cnt - 1) = 1101 & 0011 // 1 is result of modulo(hash_code, buck_cnt)
์๋ฃ๊ตฌ์กฐ๋ฅผ ๊ฒฐ์ ํ์ผ๋ spt์ ๊ด๋ จ๋ ํจ์๋ฅผ ๊ตฌํํด์ฃผ๋ฉด ๋๋ค. ๊ธฐ์กด ํด์ ์ฝ๋์ ์๋ ํจ์๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉํ๋ค.
supplemental_page_table_init
: hash_init์ ์ฝํ๊ณ , hash_hash_func์ (hash_find์ ํ์ํ) hash_less_func์ ๋ฃ์ด์ค๋ค.spt_find_page
: ๊ฐ์์ฃผ์๊ฐ์ ๊ธฐ์ค์ผ๋ก spt๋ฅผ ๊ฒ์ํ์ฌ ๋ฐํํ๋ค.spt_insert_page
: ํ์ด์ง๋ฅผ ํด์ ํ ์ด๋ธ์ ์ฝ์ ํ๋ค.
struct frame
/* The representation of "frame" */
struct frame {
void *kva; /* kernel virtual address */
struct page *page;
};
๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ํ ๊ตฌ์กฐ์ฒด์ด๋ค. palloc_get_page
๋ก ๋ฐ์์จ ๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ์ kva, kernel virtual address๋ฅผ ์ ์ฅํ๋ค. ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๋ชจ๋ ์ฌ์ฉํด ์ค์ ๋์คํฌ ๊ณต๊ฐ์ผ๋ก evictํ ๊ฒฝ์ฐ์ ๊ฐ์ด ํ๋ ์์ ๊ด๋ฆฌํ ๋ ํ๋ ์ ํ
์ด๋ธ๊ณผ ํ๋ ์ ๊ตฌ์กฐ์ฒด๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ ๋ค.
๐ ์ปค๋ ๊ฐ์ ์ฃผ์?
pintos ์ฝ๋๋ฅผ ์ง๋ค ๋ณด๋ฉด ๋ ๊ฐ์ง ์ฃผ์์ฒด๊ณ๋ฅผ ๋ง์ฃผํ๊ฒ ๋๋ค. ํ๋๋ pml4๋ฅผ ์ฌ์ฉํ ์ฃผ์์ฒด๊ณ๋ก, ๊ฐ ๋ ๋ฒจ์ ํ์ด์ง ํ
์ด๋ธ์ ์คํ์
์ 9๋นํธ์ฉ, ๊ทธ๋ฆฌ๊ณ ํ๋ ์ ์คํ์
์ 12๋นํธ ์ ์ฅํ๊ณ ์๋ ๊ฐ์์ฃผ์๋ค. ๋ค๋ฅธ ํ๋๋ ์ปค๋์ ์ฃผ์๊ณต๊ฐ์ ํน์ ํ๊ธฐ ์ํด ์ค์ ๋ ๋ผ์ธ์ธ KERN_BASE
๋ฅผ ๋ํ๊ฑฐ๋ ๋บ์ผ๋ก์ ๊ฐ์์ฃผ์์ ๋ฌผ๋ฆฌ์ฃผ์๋ฅผ ๋งคํํ๋ ์ฃผ์์ฒด๊ณ๋ก, ์ปค๋ ์ฝ๋์์ ์๋ํ๋ค. ..? ์ด ๋ถ๋ถ์ ์ข ๋ ์๊ธฐ ์ํด์๋ palloc.c
์ palloc_init
์ ๋ณด์์ผ ํ ๊ฒ ๊ฐ๋ค..
๐ loader.S
์ pml4 ๋ง๋๋ ๋ถ๋ถ
/* loader.h */
/* Physical address of kernel base. */
#define LOADER_KERN_BASE 0x8004000000
/* start.S */
#define RELOC(x) (x - LOADER_KERN_BASE)
...
#### Create page directory and page table and
#### set page directory base register (cr3).
setup_page_table:
# 1. fill boot_pml4e with zeros
lea (RELOC(boot_pml4e)), %edi // boot_pml4e์์ LOADER_KERN_BASE๋ฅผ ๋นผ์ %edi ๋ ์ง์คํฐ์ ์ ์ฅ
xor %eax, %eax // %eax๋ฅผ 0์ผ๋ก ์ด๊ธฐํ
mov $0x400, %ecx // %ecx = $0x400 (1024)
rep stosl (%edi) // %eax๋ฅผ %edi๊ฐ ๊ฐ๋ฆฌํค๋ ์์น์ ์ ์ฅํ๊ณ %edi๋ฅผ ์ฆ๊ฐ์ํค๋ ๊ฒ์ %ecx๋งํผ ์ํํ๋ค.
# 2. set pdpts
lea (RELOC(boot_pml4e)), %edi // pml4 physical addr
lea (RELOC(boot_pdpt1)), %ebx // pdpt1 physical addr
orl $(PTE_P | PTE_W), %ebx // pdpt1 is p & w
mov %ebx, (%edi) // pml4 save pdpt1
lea (RELOC(boot_pdpt2)), %ebx // pdpt2 physical addr
orl $(PTE_P | PTE_W), %ebx // pdpt2 is p & w
mov %ebx, 8(%edi) // pml4 save pdpt2
# 3. set pdpes
lea (RELOC(boot_pdpt1)), %edi // pdpt1 physical addr
lea (RELOC(boot_pde1)), %ebx // pde1 physical addr
orl $(PTE_P | PTE_W), %ebx // pde1 is p & w
mov %ebx, (%edi) // pdpt1 save pde1
lea (RELOC(boot_pdpt2)), %edi // pdpt2 physical addr
lea (RELOC(boot_pde2)), %ebx // pde2 physical addr
orl $(PTE_P | PTE_W), %ebx // pde2 is p & w
mov %ebx, (%edi) // pdpt2 save pde2
# 4. setup pdes
mov $128, %ecx
lea (RELOC(boot_pde1)), %ebx // pde1 physical addr
lea (RELOC(boot_pde2)), %edx // pde2 physical addr
add $256, %edx // %edx = 256 (2^8)
mov $(PTE_P | PTE_W | 0x180), %eax // 0x183
fill_pdes:
mov %eax, (%ebx) // pde1 = %eax
mov %eax, (%edx) // pde2 = %eax
add $8, %ebx // next
add $8, %edx // next
add $0x200000, %eax // %eax += 2MB
dec %ecx // %ecx --
cmp $0, %ecx // %ecx = 128, loops 128
jne fill_pdes
# 5. Load page directory base register (cr3).
lea (RELOC(boot_pml4e)), %eax
mov %eax, %cr3
...
// reserve 0x1000 (4096) bytes memory.
boot_pml4e:
.space 0x1000
boot_pdpt1:
.space 0x1000
boot_pdpt2:
.space 0x1000
boot_pde1:
.space 0x1000
boot_pde2:
.space 0x1000
๐ ์์๋ณผ ๋ด์ฉ๋ค..
- RELOC ๋งคํฌ๋ก๋ฅผ ํตํด kernel virtual address์์ physical address๋ก ๋ฐ๊พธ์ด์ pte์ ๊ธฐ๋กํ๊ณ ์๋๋ฐ, ๊ทธ๋ ๋ค๋ฉด kernel va์ pa์ ๋งคํ์ด ์ธ์ ๊ฐ ์ฝ๋์์์ ์ด๋ฃจ์ด์ง ์ํ์ผ ๊ฒ ๊ฐ๋ค. ๊ทธ ์์ ์ ํ๋ ๋ถ๋ถ์ ์ด๋์ ์๋์ง?
page_init
์์ ๋ง๋๋base_pml4
๋์ ๋ญ๊ฐ ๋ค๋ฅธ์ง? โbase_pml4
๋ ๋ชจ๋ ์ ์ ํ๋ก์ธ์ค๊ฐ ์ผ์ฐจ์ ์ผ๋ก ์์ํ๋(?) ๋ด์ฉ์ด๋ค.base_pml4
์๋ ์ปค๋ ์ฝ๋๊ฐ write-protectํ๊ฒ ์ฃผ์ ์ง์ ์ด ๋์ด ์๋๋ฐ,pml4_create
์์ ๋ฐ๋ก ์ด pml4์ ๋ด์ฉ์ ๊ฐ์ ธ์จ๋ค.pml4_activate(NULL);
๊ฐ์ ์ฝ๋๋ฅผ ์คํํ๋ฉด ๋ด๋ถ์ ์ผ๋กpml4 ? pml4 : base_pml4
์์ผ๋กbase_pml4
๊ฐ cr3 ๋ ์ง์คํฐ์ ์ฌ๋ผ๊ฐ๋ค.
/* Creates a new page map level 4 (pml4) has mappings for kernel
* virtual addresses, but none for user virtual addresses.
* Returns the new page directory, or a null pointer if memory
* allocation fails. */
uint64_t *pml4_create(void) {
uint64_t *pml4 = palloc_get_page(0);
if (pml4) memcpy(pml4, base_pml4, PGSIZE);
return pml4;
}
02) Anonymous Page
๋์คํฌ ๊ธฐ๋ฐ์ด ์๋ ํ์ด์ง, ์ฆ ์ต๋ช ํ์ด์ง๋ ์ฃผ๋ก ์คํ ๋๋ ํ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ฐ๋ฆฌํจ๋ค.
- Anonymous page: ํ์ผ๊ณผ ๋งคํ๋์ง ์์ ํ์ด์ง
- File-backed page: ๋์คํฌ์ ์๋ ํ์ผ๊ณผ ์ง์ ๋งคํ๋ ํ์ด์ง๋ก, ์ด ํ์ด์ง์์ ๋ณ๊ฒฝ๋ ๋ด์ฉ์ ํ์ผ์๋ ๋ฐ์๋์ด์ผ ํจ.
๐ ELF ํ์ผ์ ๋ก๋ํ ๋ file-backed๊ฐ ์๋ anonymous๋ก ์ง์ ํ๋ ์ด์ ?
static bool load_segment(struct file *file, off_t ofs, uint8_t *upage,
uint32_t read_bytes, uint32_t zero_bytes,
bool writable) {
...
while (read_bytes > 0 || zero_bytes > 0) {
...
if (!vm_alloc_page_with_initializer(VM_ANON, upage, writable,
lazy_load_segment, aux)) {
return false;
}
File-backed page๋ ํ์ด์ง์ ๋ณ๊ฒฝ์ฌํญ์ ๋์คํฌ์ ํ์ผ์ ์ ์ฅํด์ผ ํ๋ ํ์ด์ง ์ข
๋ฅ๋ฅผ ๋ํ๋ด๊ธฐ ์ํ ํ์
์ด๋ค. ELF ํ์ผ์ ์ฝ๋์ ๋ฐ์ดํฐ(.data, .bss) ์์ญ์ ๋ณ๊ฒฝ๋์๋ค๊ณ ํด์ ๋์คํฌ์ ๋ฐ์๋๋ฉด ์ ๋๋ค. ๋ฐ๋ผ์ VM_ANON
์ผ๋ก initialize ํ๋๋ก ํ์
์ ์ง์ ํ๋ค. (๊ทธ๋ฆฌ๊ณ swap out๋์๋ค๊ฐ ๋ค์ swap in ๋์์ ๋๋ ์ด์ ์ ๋ณ๊ฒฝ๋ด์ฉ์ ์ ์งํด์ผ ํ๋ค. ์ฆ, ํ์ผ์ด ์๋ swap disk์ ๊ธฐ๋ก๋์ด์ผ ํ๋ค.)
Lazy loading segments
ELF ์คํ ํ์ผ์ lazyํ๊ฒ loadํด๋ณด์
bool vm_alloc_page_with_initializer(enum vm_type type, void *upage,
bool writable, vm_initializer *init,
void *aux);
VM์ load_segment
ํจ์๋ void* kpage = palloc_get_page(PAL_USER | PAL_ZERO);
๋์ ์ด ํจ์๋ฅผ ๋ถ๋ฌ์ ๊ฐ์์ฃผ์๊ณต๊ฐ์ ์์ฝํด๋๊ณ , ์ค์ ํด๋น ์ฃผ์์์ ํ์ด์ง ํดํธ๊ฐ ๋ฐ์ํ์ ๋ ๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ์ ๋งคํํด์ค๋ค. ์์ฝ๋ ๊ฐ์์ฃผ์๊ณต๊ฐ์์ ์๊ธฐ ์ํด spt๋ฅผ ํ์ฉํ๋ค. ์ฆ, ์ ํจ์๋ฅผ ์คํํ๋ฉด, 4KB ๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๋ฐ๋ ๊ฒ์ด ์๋๋ผ, struct page
๋ผ๋ ์์ ๊ตฌ์กฐ์ฒด๋ง ๋ง๋ค์ด์ ํ์ฌ ์ค๋ ๋(๋๋ ์ ์ ํ๋ก์ธ์ค)์ spt์ ๋ฃ์ด ๋๋ค.
struct page* page = calloc(1, sizeof(struct page));
switch(type)
case VM_ANON:
uninit_new(page, upage, init, type, aux, anon_initializer);
case VM_FILE:
uninit_new(page, upage, init, type, aux, file_backed_initializer);
...
spt_insert_page(&thread_current()->spt, page);
uninit.c
์ ์๋ uninit_new
ํจ์๋ ์ฃผ์ด์ง ์ธ์๋ฅผ page ๊ตฌ์กฐ์ฒด์ ํ๋์ ๋ฃ์ด์ฃผ๋ ํจ์์ด๋ค. ์์ง ์ด๊ธฐํ๋์ง ์์, ์ฆ ๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ์ ๋งคํ๋์ง ์์ ํ์ด์ง๋ฅผ ์๋ฏธํ๋ค. ์ธ์๋ก ์ ๋ฌ๋ type์ ๋ฐ๋ผ initializer ํจ์๋ฅผ ๋ฃ์ด ์ฃผ๋ฉด page->uninit->initializer
ํ๋์ ๋ฃ์ด๋์๋ค๊ฐ ์คํ๋๋ค. (์ธ์ ์คํ๋๋๋ฉด!! uninit์ swap_in
๋)
load_segment
ํจ์๋ ์์ ๊ฐ์ด ๊ฐ์์ฃผ์๊ณต๊ฐ์ ์์ฝํด๋๋ ๊ฒ์ผ๋ก ์ข
๋ฃ๋๋ค. ๊ทธ ํ ํ๋ก์ธ์ค๊ฐ ์คํ๋์ด ํด๋น ํ์ด์ง์ fault๊ฐ ๋ฐ์ํ๋ฉด ์ค์ ELF ํ์ผ์ ๋ด์ฉ์ ์ฝ์ด์ ๋ก๋ํด์ฃผ์ด์ผ ํ๋ค.
// init.c ๊ณผ์ ์ค ํ์ด์ง ํดํธ์ vec_no์ page_fault ํจ์๋ฅผ ๋งคํํด ๋๋ค.
// ํ์ด๋จธ ์ธํฐ๋ฝํธ๋ intr_register_ext๋ก ์ด๊ธฐํํ์ง๋ง
// page fault๋ internal exception์ด๋ฏ๋ก intr_register_int๋ก ์ด๊ธฐํ.
void exception_init(void) {
...
intr_register_int(14, 0, INTR_OFF, page_fault, "#PF Page-Fault Exception");
}
// intr_handler ํจ์ ์์์ page_fault๊ฐ ์ฝ ๋๋ค.
static void page_fault(struct intr_frame *f) {
bool not_present; /* True: not-present page, false: writing r/o page. */
bool write; /* True: access was write, false: access was read. */
bool user; /* True: access by user, false: access by kernel. */
void *fault_addr; /* Fault address. */
struct thread *curr; /* Current thread. */
fault_addr = (void *)rcr2();
/* Turn interrupts back on (they were only off so that we could
be assured of reading CR2 before it changed). */
intr_enable();
/* Determine cause. */
not_present = (f->error_code & PF_P) == 0;
write = (f->error_code & PF_W) != 0;
user = (f->error_code & PF_U) != 0;
#ifdef VM
/* For project 3 and later. */
if (vm_try_handle_fault(f, fault_addr, user, write, not_present)) return;
#endif
exception.c
์ exception_init
์์ ํ์ด์ง ํดํธ์ vec_no
์ธ 14๋ฒ๊ณผ page_fault
ํจ์๊ฐ ๋งคํ๋๊ณ , 14๋ฒ ์ธํฐ๋ฝํธ๊ฐ ๋ฐ์ํ๋ฉด ์ด ํจ์๊ฐ ์คํ๋๋ค. ๊ทธ ์์ vm_try_handle_fault
๊ฐ ์ฐ๋ฆฌ๊ฐ ๊ตฌํํด์ผ ํ๋ ํจ์์ด๋ค.
์๊ตฌ ํ์ด์ง์ ๊ตฌํํ๋ฏ๋ก, ํ์ด์ง ํดํธ๊ฐ ๋ฐ์ํ๋ ์๋๋ฆฌ์ค ์ค ๋จ์ bad ptr์ด ์๋ lazy loading ์ธ ๊ฒฝ์ฐ๊ฐ ์๊ฒผ๋ค.
+) bad pointer๊ฐ ์๋ ์ธ ๊ฐ์ง fault case
- lazy loading: ํ์ด์ง์ ํด๋น ํ์ผ๋ก๋ถํฐ ์ฝ์ด์ ๋ฐ์ดํฐ๋ฅผ ๋ก๋ํด์ค์ผ ํ๋ค. ๋๋ ์ต๋ช ํ์ด์ง์ธ ๊ฒฝ์ฐ ๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋นํด ๋งคํํด์ผ ํ๋ค.
- write-protect: ์ฐ๊ธฐ ๋ณดํธ๋ ํ์ด์ง์ ๋ํ ์ฐ๊ธฐ ์ ๊ทผ์ธ ๊ฒฝ์ฐ ์ค์ ๋ก fault๊ฐ ๋ฐ์ํด์ผ ํ๋ค.
- swap-out page: ํ์ด์ง ๊ต์ฒด๋ก ์ธํด ํ์ด์ง๊ฐ ์ค์ ๋์คํฌ๋ก out๋ ์ํฉ์ด๋ผ๋ฉด, ๋ค์ inํด์ผ ํ๋ค.
lazy loading๋ง ์๊ฐํด ๋ณด๋ฉด, ๋ง์ฝ fault๊ฐ ๋ฐ์ํ address๊ฐ ์ด์ ์ ์์ฝ๋ ์ฃผ์๊ณต๊ฐ์ด๋ผ๋ฉด, spt์์ ์ฐพ์ ์ ์๋ค. ๋ฐ๋ผ์ spt๋ฅผ ๊ฒ์ํด์ ํด๋น ๊ฐ์์ฃผ์๋ฅผ ๊ฐ๋ ํ์ด์ง ์ ๋ณด๊ฐ ์๋์ง ํ์ธํ๊ณ , ์๋ค๋ฉด ๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๋งคํํด์ค๋ค. ์๋ค๋ฉด return false ํ๋ค.
bool vm_do_claim_page(struct page* page) {
struct frame* frame = vm_get_frame();
frame->page = page;
page->frame = frame;
/* mark page as present. */
page->flags = page->flags | PTE_P;
return swap_in(page, frame->kva);
}
๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋นํ๊ณ , ๊ตฌ์กฐ์ฒด๋ผ๋ฆฌ ์ฐ๊ฒฐํ ํ swap_in
์ ์คํํ๋ค. ์ด ๋๋ uninit_operation
์ swap_in
์ด ์คํ๋๋๋ฐ, ์ด๋ uninit_initialize
ํจ์์ด๋ค.
/* Initalize the page on first fault */
static bool uninit_initialize(struct page *page, void *kva) {
struct thread* curr = thread_current();
struct uninit_page *uninit = &page->uninit;
/* Fetch first, page_initialize may overwrite the values */
vm_initializer *init = uninit->init;
void *aux = uninit->aux;
return uninit->page_initializer(page, uninit->type, kva) &&
(init ? init(page, aux) : true) && install_page(page);
}
์ฌ๊ธฐ์ ์ด์ ์ vm_alloc_page_with_initializer
์์ ์ธ์๋ก ๋๊ฒผ๋ init
, aux
์ initializer
๊ฐ ์ฌ์ฉ๋๋ ๊ฒ์ ๋ณผ ์ ์๋ค. anon_initializer
๋๋ file_backed_initializer
๋ฅผ ์คํํ๊ณ , install_page
๋ก ํ์ฌ ์ค๋ ๋์ pml4
์ ๋งคํ์ ๋ง๋ค์ด ์ฃผ์๋ค. ์ด ํจ์๋ฅผ ์คํํจ์ผ๋ก์ lazy loading ๊ณผ์ ์ด ๋ง๋ฌด๋ฆฌ๋๋ค.
๋ ๋ฒ์งธ ๊ทธ๋ฆผ์ ํ๋ ๋น ์ง ๊ฒ ์๋๋ฐ, ๋ง์ง๋ง์ผ๋ก ํด๋น ๊ฐ์์ฃผ์์ ํ ๋น๋ ๋ฉ๋ชจ๋ฆฌ์ ๋ฌผ๋ฆฌ์ฃผ์๋ฅผ ํ์ฌ ์ค๋ ๋์ pml4์ setํด์ฃผ์ด์ผ ํ๋ค.
Copy spt table
fork
์์คํ
์ฝ์ ํธ์ถํ ๋, ๋ถ๋ชจ์ ์์ ๊ฐ์ spt table์ ๋ณต์ ํด ์ฃผ์ด์ผ ํ๋ค. ์ฃผ์ํ ์ ์, file_info
์ ๊ฐ์ด malloc
์ผ๋ก ํ ๋น๋ฐ์ ๊ตฌ์กฐ์ฒด ์ ๋ณด๋ ๋ณต์ ํด์ผ ํ๋ค๋ ์ ์ด๋ค. ๋ฐ๋ผ์ ํ์
๋ณ๋ก ๋ณต์ ๋ฅผ ์ ํด์ฃผ๋ ๊ฒ ์ค์ํ๋ค.
๋ ํ๋ก์ธ์ค fork๋ฅผ ํ ๋, lazyํ๊ฒ loadํ ํ์ผ์ด ๋ถ๋ชจ ํน์ ์์์์ ๋จผ์ ๋ซํ ๋ฒ๋ฆฌ๋ ๊ฒฝ์ฐ๋ฅผ ์ฃผ์ํด์ผ ํ๋ค. ๋ฐ๋ผ์ ๋์ผํ ํ์ผ์ file_duplicate
๊ณผ ๊ฐ์ ํจ์๋ฅผ ์ด์ฉํด ํ๋ฒ ๋ ์ด์ด ์ฃผ๋ ๊ฒ์ด ์์ ํ๋ค. (ํนํ ELF ์คํ ํ์ผ์ ๊ฒฝ์ฐ)
static void spt_copy_page(struct hash_elem *e, void *aux) {
struct supplemental_page_table *dsc_spt =
(struct supplemental_page_table *)aux;
struct hash *dsc_hash = &dsc_spt->hash;
struct page *src_page = hash_entry(e, struct page, elem);
/* Copy spt entries. */
struct page *dsc_page = calloc(1, sizeof(struct page));
memcpy(dsc_page, src_page, sizeof(struct page));
/* Deconnect from parent's hash table. */
memset(&dsc_page->elem, 0, sizeof(struct hash_elem));
hash_insert(dsc_hash, &dsc_page->elem);
if (!pg_present(src_page)) {
/* If uninitialized segement page, copy file info. */
struct file_info *dsc_aux;
struct file_info *src_aux = (struct file_info *)src_page->uninit.aux;
dsc_aux = calloc(1, sizeof(struct file_info));
memcpy(dsc_aux, src_aux, sizeof(struct file_info));
dsc_page->uninit.aux = dsc_aux;
} else {
/* Claim page if present. */
struct frame *dsc_frame = vm_get_frame();
ASSERT(src_page->frame->kva)
ASSERT(dsc_page->frame->kva)
dsc_page->frame = dsc_frame;
dsc_frame->page = dsc_page;
memcpy(dsc_page->frame->kva, src_page->frame->kva, PGSIZE);
install_page(dsc_page);
}
}
03) Stack Growth
์คํ์ ํฌ๊ธฐ๋ ์ด๊ธฐ์ 4KB๋ก ์ธํ
๋๋ค. ์คํ์ setup_stack
ํจ์๊ฐ ๋ฆฌํด๋๊ธฐ ์ ์ ์ค์ ๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋น๋ฐ๋๋ก ๊ตฌํํ๋๋ฐ, ์ด๋ ์คํํ์ผ load๊ณผ์ ์์ setup_stack
์ด ํธ์ถ๋ ์งํ ์คํํ์ผ์ ์ธ์๋ฅผ ์คํ์ ์์์ฃผ๊ธฐ ๋๋ฌธ์ด๋ค. ๋ง์ฝ ์ฆ์ 1๊ฐ ํ์ด์ง๋ฅผ ํ ๋น๋ฐ์ง ์๋๋ค๋ฉด ์ธ์๋ฅผ ์๋ ๊ณผ์ ์์ ํดํธ๊ฐ ๋ฐ์ํ๊ณ , ๊ทธ ๋ ์คํ์ด ๋ง๋ค์ด์ง์๋ ์(๊ธด ์)๋ค. ํ์ง๋ง lazy loading์ด ์ค์ ๋ก ์ ๊ทผ์ด ์ธ์ ์ด๋ฃจ์ด์ง ์ง ๋ชจ๋ฅด๊ธฐ ๋๋ฌธ์ ์ ๊ทผ ํ์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋นํด์ฃผ๋ ์ ๋ต ์ด๋ผ๋ ์ ์์, ์ ๊ทผ์ด ์ด๋ฃจ์ด์ง ๊ฒ์์ ์๋ ๋ฉ๋ชจ๋ฆฌ์ ๋ํด์๋ ์ฆ์ ํ ๋นํด ์ฃผ๋ ๊ฒ์ด ํฉ๋ฆฌ์ ์ผ ์ ์๋ค.
๋ง์ฝ ์คํ์ ๊ณต๊ฐ์ด ๋ถ์กฑํ๋ค๋ฉด ์คํ์ ์ต๋ 1MB๊น์ง ๋๋ ค ์ฃผ์ด์ผ ํ๋ค. ์ด๋ฅผ vm_try_handle_fault
์์ ์ด๋ป๊ฒ ๊ตฌํํ ์ ์์๊น? ์ด ๊ฒฝ์ฐ fault๊ฐ ๋ฐ์ํ address๋ spt์ ์์ ๊ฒ์ด๋ผ๋ ์ฌ์ค์ ์ง์ํ ์ ์๋ค.
bool vm_try_handle_fault(struct intr_frame *f, void *addr, bool user,
bool write, bool not_present) {
struct supplemental_page_table *spt = &thread_current()->spt;
void *upage = pg_round_down(addr);
void *curr_rsp = (void *)f->rsp;
/* Validate stack overflow. */
if (STACK_LIMIT < addr && addr < spt->stack_bottom) {
/* If current stack is not full, not a stack overflow. */
if (curr_rsp != addr) return false;
/* If stack overflow */
return vm_stack_growth(upage);
}
if(STACK_LIMIT < addr && addr < spt->stack_bottom && curr_rsp == addr)
์ด๋ฅผ ํตํด ์คํ์ ๋๋ฆฌ๋ ค๋ ์๋์์ ์ฒดํฌํ ์ ์๋ค. ์คํ์ ํ์ฅํ๋ ค๊ณ ํ๋ฉด, rsp๊ฐ์ด ์คํ ์์ญ์ ๋ฐ์ผ๋ก ๊ฐ์ํ ๋ค์, ํด๋น rsp๊ฐ ์ฐธ์กฐํ๋ ์ฃผ์์ ์ ๊ทผํ ๊ฒ์ด๋ค. ๋ฐ๋ผ์ fault๊ฐ ๋ฐ์ํ ์ฃผ์์ rsp๊ฐ๊ณผ ๊ฐ๋ค๋ฉด, ์ ํจํ ์คํ ํ์ฅ ์๋๋ก ๋ณผ ์ ์์ ๊ฒ์ด๋ค. (๊ทธ ์ ์ STACK_LIMIT
๊ณผ spt->stack_bottom
์ ๊ธฐ์ค์ผ๋ก stack address์์ ์ฒดํฌํ๊ณ , rsp์ ๋น๊ตํ์ฌ ์คํ ํ์ฅ ์๋์ ์ ํจ์ฑ์ ๊ฒ์ฆํ๋ค.)
/* Growing the stack. */
static bool vm_stack_growth(void *addr) {
/* If addr exceeds STACK_LIMIT, return false. */
if (addr <= STACK_LIMIT) {
return false;
}
struct supplemental_page_table *spt = &thread_current()->spt;
spt->stack_bottom = addr;
return vm_alloc_page(VM_ANON, addr, true);
}
bool vm_alloc_page_with_initializer(enum vm_type type, void *upage,
bool writable, vm_initializer *init,
void *aux) {
// make page struct and insert spt
...
/* If stack page, claim immediately. */
if (upage == spt->stack_bottom) {
if (!vm_do_claim_page(page)) goto err;
}
vm_alloc_page_with_initializer
ํจ์๋ฅผ ์คํ ํ์ด์ง์ธ ๊ฒฝ์ฐ ์ฆ์ claimํ๋๋ก ์ง ๋์์ผ๋ฏ๋ก vm_stack_growth
์์๋ spt์ stack_bottom
๊ฐ์ PGSIZE
๋งํผ ๋๋ฆฐ ํ vm_alloc_page
๋ฅผ ์ฝ ํ๊ธฐ๋ง ํ๋ฉด ๋๋ค.
๐ ์๋์ ๊ฐ์ ์ฝ๋์์๋ fault addr๊ฐ rsp์ ๋ค๋ฅธ ์ฃผ์์ธ ๊ฑฐ ์๋?
int main() {
char arr[65536]; // 64KB
arr[0] = 4;
return 0;
}
๋ฐฐ์ด์ ์์๊ฐ 4KB๋ฅผ ์ด๊ณผํ๋ 65536๊ฐ ์ด๊ณ , 0๋ฒ์งธ ์์(๊ฐ์ฅ ๋ฎ์ ์ฃผ์)์ ์ ๊ทผํ๋ฏ๋ก fault address๋ rsp + 65536 ์ด ๋์ง ์์๊น? ํ์ง๋ง ๊ทธ๋ ์ง ์๋ค.. ์์ ๊ฐ์ c์ฝ๋๋ฅผ gcc ์ปดํ์ผ๋ฌ๋ก ์ปดํ์ผํ๋ฉด ์๋์ ๊ฐ์ ์ฝ๋๋ฅผ ๋ฑ๋๋ค.
main:
.LFB0:
.cfi_startproc
endbr64
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
leaq -61440(%rsp), %r11
.LPSRL0:
subq $4096, %rsp
orq $0, (%rsp) // ๐ฅ fault!
cmpq %r11, %rsp
jne .LPSRL0
subq $3976, %rsp
movb $4, -65536(%rbp)
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFB0
๋ผ๋ฒจ์ ๋ง์ง๋ง ๋ผ์ธ์ ๋ณด๋ฉด %rsp๊ฐ์์ 61440๋ฅผ ๋บ ๊ฐ์ %r11 ๋ ์ง์คํฐ์ ์ ์ฅํ๊ณ ์๋ค. ์ด๋ ๋ฐฐ์ด์ ํฌ๊ธฐ์ ๋น๊ตํด ๋ ๋๋ ค ์ฃผ์ด์ผ ํ๋ ์คํ ์ฌ์ด์ฆ๋ฅผ ๊ณ์ฐํ๊ณ ์๋ ๊ฒ์ผ๋ก ๋ณด์ธ๋ค. ๊ทธ๋ฆฌ๊ณ , %r11๊ณผ ํ์ฌ %rsp๊ฐ์ ๋น๊ตํ๋ฉด์ $4096์ฉ ์คํ ์์ญ์ ๋๋ ค์ฃผ๊ณ ์๋ค. ์ด ๋ orq $0, (%rsp)
๋ผ์ธ์ ์ํด ์ค์ ์ ์ผ๋ก ํ์ด์ง ํดํธ๊ฐ ๋ฐ์ํ๋๋ฐ, ์ด๋ %rsp๊ฐ์ ์ ๊ทผํด 0๊ณผ์ or์ฐ์ฐ์ ์ํํ๊ธฐ ๋๋ฌธ์ด๋ค. (0๊ณผ์ or์ด๋ฏ๋ก ์ฐ์ฐ ๊ฒฐ๊ณผ๋ ๋ฐ๋์ง ์๋๋ค. ํดํธ๋ฅผ ๋ฐ์์ํค๋ ค๋ ์๋๋ก ๋ณด์ธ๋ค.)
๐ ๊ทธ๋ฌ๋ฉด ๋ฐฐ์ด์ ์ ์ธํ๋ฉด์ ์คํ ์ฌ์ด์ฆ๋ฅผ ๋๋ ค์ฃผ๋๋ฐ, ์ด๊ฒ์ ์คํ์ lazyํ์ง ์๊ฒ ํ ๋นํ๋ ๊ฒ ์๋๊ฐ?
lazy load๋ ์ด์์ฒด์ ๊ฐ ํ๋ ์ผ์ด๊ณ , page fault๋ฅผ ์ผ์ผํค๋ฉด์ ์คํ์ ๋๋ ค์ฃผ๋ ๊ฒ์ ์ฌ์ฉ์ ํ๋ก๊ทธ๋จ์ด๋ค. ์ด๋ป๊ฒ ๋ณด๋ฉด, ์ด์์ฒด์ ๊ฐ lazy load๋ผ๋ ๋ฐฉ์์ ํํ๊ณ ์๊ธฐ ๋๋ฌธ์ ์ ์ ํ๋ก๊ทธ๋จ์ด page fault๋ฅผ ๊ณ ์์ ์ผ๋ก ๋ฐ์์ํค๋ฉฐ ์คํ์ ๋๋ฆฌ๋๋ก ์ปดํ์ผ๋๋ ๊ฒ์ด๋ค.
+) ์ด ๋ถ๋ถ์ ๋ํ GPT ์ฝ๋ฉํธ๋ฅผ ๋ฌ์๋๋ค: ์ปดํ์ผ๋ฌ๊ฐ ์คํ์ ๋๋ฆฌ๋ ์ฝ๋๋ฅผ ์์ฑํ๋ ์ด์ ๋ ์คํ์ lazyํ๊ฒ ํ ๋นํ๋ ์ด์์ฒด์ ์ ์ํธ ์์ฉํ๊ธฐ ์ํจ์ ๋๋ค. Lazy loading์ ์ด์์ฒด์ ์์ ํ์ด์ง ํ ๋น์ ํจ์จ์ ์ผ๋ก ํ๊ธฐ ์ํ ์ ๋ต์ ๋๋ค. ์คํ ์์ญ์ด ํ์ฅ๋๋ฉด, ํ๋ก๊ทธ๋จ์ ์ค์ ๋ก ํด๋น ์์ญ์ ์ ๊ทผํ ๋๊น์ง ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋น๋ฐ์ง ์์ต๋๋ค. ์ด ์ ๊ทผ์ ํ์ด์ง ํดํธ๋ฅผ ๋ฐ์์ํค๊ณ , ์ด์์ฒด์ ๋ ๊ทธ ๋ ํ์ด์ง๋ฅผ ํ ๋นํฉ๋๋ค. (...) lazy loading์ ์ด์์ฒด์ ์ ๊ธฐ๋ฅ์ ๋๋ค. ๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ , ์ปดํ์ผ๋ฌ๋ ์ด๋ฌํ ์ด์์ฒด์ ์ ํน์ฑ์ ์ด์ฉํ์ฌ ์คํ ํ์ฅ ์ฝ๋๋ฅผ ์์ฑํฉ๋๋ค. ์ด๊ฒ์ ์ด์์ฒด์ ์ ํน์ฑ๊ณผ ์ํธ ์์ฉํ๋ ํ๋ก๊ทธ๋จ์ ์ต์ ํ ์์ ์ ๋๋ค.
๐ ์ ํ๋ฒ์ 65536๋งํผ rsp์์ ๋นผ์ง ์๊ณ 4096์ฉ ๋นผ๋๋ก ์ปดํ์ผ๋ ๊น?
์คํ์ ์์์ ์๋๋ก, ํ์ ์๋์์ ์๋ก ํ์ฅ๋๋ฏ๋ก ์ผ๋ฐ์ ์ธ ์ฌ์ฉ์ ํ๋ก๊ทธ๋จ์์ ๋ ์์ญ์ ์ถฉ๋ํ์ง ์๋๋ค. ๊ทธ๋ฌ๋ ์คํ ์ค๋ฒํ๋ก์ฐ ๊ณต๊ฒฉ๊ณผ ๊ฐ์ ๋ณด์ ์ํ์์ ์คํ์ ํฌ๊ธฐ๊ฐ ํ์ ์นจ๋ฒํ์ฌ ๊ณผ๋ํ๊ฒ ํ์ฅ๋๋ฉด ๋ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ด ์ถฉ๋ํ ์ ์๋ค. ์ด๋ฌํ ๊ณต๊ฒฉ์ ๋๋นํ๊ธฐ ์ํด, ์คํ์ ๋(๊ฐ์ฅ ๋ฎ์ ์ฃผ์)์๋ Red Zone ๋๋ Stack Guard Page๋ผ๊ณ ๋ถ๋ฆฌ๋ ๊ฒฝ๊ณ๊ฐ ์กด์ฌํ๋ค. ์ด ํ์ด์ง๋ ์ ๊ทผ ๊ธ์ง๋ ๊ตฌ์ญ์ผ๋ก, ํด๋น ๊ตฌ์ญ์ ์ ๊ทผํ๊ฒ ๋๋ฉด ์์คํ ์ Fault๋ฅผ ๊ฐ์งํ๊ณ ํ๋ก์ธ์ค๋ฅผ ์ข ๋ฃ์ํจ๋ค. (์ฆ, ์ด ํ์ด์ง์ ๋ํ ์ ๊ทผ์ ๊ณง ์๋ชป๋ ๋ฉ๋ชจ๋ฆฌ ์ ๊ทผ์ผ๋ก ์ธ์ง๋๋ค.) ๊ทธ๋ฐ๋ฐ ๋ง์ฝ ์ปดํ์ผ๋ฌ๊ฐ ํ๋ฒ์ ํ๋ก๊ทธ๋จ์ด ์์ฒญํ ๋งํผ ์คํ์ ํ์ฅํ๋๋ก ์ปดํ์ผํ๋ค๋ฉด ์ด Stack Guard Page๋ฅผ ์คํตํ ์ฃผ์๊ฐ์ผ๋ก rsp๊ฐ ์ค์ ๋ ์ ์๊ฒ ๋๋ค. ๋ฐ๋ผ์ ํ ํ์ด์ง ๋จ์๋ก, ๋ฐ๋ณต์ ์ผ๋ก rsp๋ฅผ ๊ฐ์์ํค๋ฉด์ ๊ธ์ง ๊ตฌ์ญ์ ์ ๊ทผํ๋์ง๋ฅผ ๊ฐ์งํ ์ ์๋๋ก ์ปดํ์ผ๋๋ค. (-fno-stack-protector ์ต์ ์ ๋๋ฉด ์ปดํ์ผ ๊ฒฐ๊ณผ๊ฐ ๋ฌ๋ผ์ง๊น? ํ์ธํด ๋ณผ ๊ฒ.)
Red Zone: wikipedia
A closer look at the stack guard page
์ฌ๊ธฐ๊น์ง ๋ค ํ์ผ๋ฉด, ์ด์ ์์ผ 1์ฃผ์ฐจ 2์ฃผ์ฐจ ์ฝ๋๊ฐ ๋ฌผ๋ฆฌ์ ์ธ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ฐ๊ณ .. ์คํ๋๊ธฐ ์์ํ๋ค. ์ด์ ๊ฐ ํ๋ก์ธ์ค๋ ์๊ตฌ ํ์ด์ง์ด๋ผ๋ ํ๋ฅญํ ์ ๋ต์ ์ฌ์ฉํด ์ ์ฒด ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๋์ฑ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ ์ ์๊ฒ ๋๋ค..
'DevLog ๐จ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[DevLog][PintOS] 3์ฃผ๊ฐ์ ํํ ์ค ํ๊ณ (1) | 2023.10.24 |
---|---|
[DevLog][PintOS] PRJ3 Virtual Memory/Memory Mapped Files to Copy-on-write (1) | 2023.10.24 |
[DevLog][PintOS] PRJ2 User Program/Out of Memory Test (0) | 2023.10.10 |
[DevLog][PintOS] PRJ1 Threads/PintOS ์ค๋ ๋๋ ์ด๋ป๊ฒ ๋์๊ฐ๊น? (0) | 2023.10.03 |
[DevLog][PintOS] PRJ1 Threads/Scheduling Algorithms (0) | 2023.10.03 |