ํ๋ก์ ํธ 2์์ ์คํ์ USER_STACK์์ ์์ํ๋ ๋จ์ผ ํ์ด์ง์์ผ๋ฉฐ, ์ด ํฌ๊ธฐ๋ฅผ 4KB๋ก ์ ํํด ์คํํ๋ค.
์ด์ ํด๋น ํํธ์์๋ ์คํ์ด ํ์ฌ ํฌ๊ธฐ๋ฅผ ์ด๊ณผํ ๋ ํ์์ ๋ฐ๋ผ ์ถ๊ฐ ํ์ด์ง๋ฅผ ํ ๋นํ๋ Stack Growth๋ฅผ ๊ตฌํํ๋ค.
Stack Growth?
: ์ ๊ทผํ ๊ฐ์์ฃผ์์ ๋งคํ๋ frame์ด ์์ด์ page fault๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ, Stack์ ๋๋ ค ์ถ๊ฐ ํ์ด์ง๋ฅผ ํ ๋นํด page fault๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐฉ์์ด๋ค.์ด๋ ๊ฐ์์ฃผ์๊ฐ stack์ ์ ๊ทผํ๋ ๊ฒฝ์ฐ์๋ง ์ ์ฉ๋๋ค.
์ฐ๋ฆฌ๊ฐ ์๊ฐํด์ผ ํ ๊ฒ์ ํฌ๊ฒ 3๊ฐ์ง๋ค.
1. ์ ๊ทผํ ๊ฐ์์ฃผ์๊ฐ stack์ธ์ง ํ๋ณ
2. stack growth๋ก ํด๊ฒฐํ ์ ์๋ ๊ฒฝ์ฐ์ธ์ง ํ๋ณ
3. stack growth ๊ธฐ๋ฅ ๊ตฌํ
pintOS์์๋ Stack์ ํฌ๊ธฐ๋ฅผ 1MB๋ก ์ ํํ๊ณ ์๋ค.
๊ทธ๋ ๋ค๋ฉด ์คํ์ ์์ญ์ 'USER_STACK'์์๋ถํฐ 'USER_STACK-1MB'์ผ ๊ฒ์ด๋ค.
์คํ์ ๋์ ์ฃผ์์์ ๋ฎ์ ์ฃผ์๋ก ์ปค์ง๊ธฐ ๋๋ฌธ์ -1MB๋ฅผ ํด์ผ ํ๋ค.
์ด๋ฅผ ์ฝ๋๋ก ๊ตฌํํ๋ฉด 'USER_STACK - (1 << 20)'์ด๋ค.
Bit masking์ผ๋ก ํํํ ๊ฒ์ผ๋ก, 1 << 20 = 2์ 20์น = 1MB
์ฆ, USER_STACK - 1MB = ์คํ์ด ๊ฐ์ง ์ ์๋ ์ต๋ ํฌ๊ธฐ์ ์ตํ๋จ ์ฃผ์๊ฐ ๋๋ค.
if(USER_STACK - (1 << 20) <= addr && addr <= USER_STACK){
= addr์ด ์คํ ์์ญ ๋ด๋ฅผ ๊ฐ๋ฆฌํจ๋ค๋ ๊ฑธ ์๋ฏธ
}
๊ทธ๋ฐ๋ฐ ์ ๊ทผํ ๊ฐ์์ฃผ์๊ฐ stack์ธ ๊ฒฝ์ฐ๋๋ผ๋ ๋ชจ๋ stack growth๋ก ํด๊ฒฐํ ์ ์๋ ๊ฑด ์๋๋ค.
์ ์ ํ๋ก๊ทธ๋จ์ ์คํ ํฌ์ธํฐ ์๋์ ์คํ์ ์ธ ๊ฒฝ์ฐ ๋ฒ๊ทธ๊ฐ ๋ฐ์ํ๊ธฐ ๋๋ฌธ์, 'USER_STACK ~ ์คํ ํฌ์ธํฐ๋ณด๋ค ๋์ ์ฃผ์ ๊ฐ'์ธ ๊ฒฝ์ฐ์๋ง stack growth๋ฅผ ์ ์ฉํ ์ ์๋ค.
์ ์คํ ํฌ์ธํฐ ์๋์์ stack growth๋ฅผ ์ ์ฉํ ์ ์์๊น?? ๐ค
: ์คํ ํฌ์ธํฐ๋ณด๋ค ๋ฎ์ ์ฃผ์๋ฅผ ๊ฐ๋ฆฌํฌ ๋ ํด๋น ์์น์ stack growth๋ฅผ ์ ์ฉ์ํค๋ฉด ์ ํ์ด์ง๋ฅผ ํ ๋นํ๊ณ ๋ฐ์ดํฐ๋ฅผ ์จ๋๋๋ค๋ฉด, ๋ฐ์ดํฐ๊ฐ ์ค์ผ๋ ์ ์๋ค.
-> ์ด ๋ง์ด ๋ฌด์จ ์๋ฏธ๋?
์ด์์ฒด์ ๊ฐ ์คํ๋๋ค๊ฐ ํ๋ก์ธ์ค๋ฅผ ์ค๋จ์ํฌ ๋ ์คํ๋๋ ์ ๋ณด๋ฅผ stack์ ์ ์ฅํ๊ฒ ๋๋๋ฐ, ์คํ ํฌ์ธํฐ ์๋์ ๋ฐ์ดํฐ๋ฅผ ์จ๋์๋ค๋ฉด? ๋ฐ์ดํฐ๊ฐ ๋ฎ์ด์์์ง๋ฉด์ ๋ณ๊ฒฝ๋ ์ ์๋ค.
๋ํ ์ดํ์ rsp๊ฐ ๋ด๋ ค์ค๋ฉด์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ ํ ๋๋ ๋ง์ฐฌ๊ฐ์ง๋ก ๋ฐ์ดํฐ๊ฐ ๋ฎ์ด์์์ง ์ ์๋ค.
๊ทธ๋ฐ๋ฐ ์คํ ํฌ์ธํฐ๋ณด๋ค ๋์์ง ๋ฎ์์ง๋ฅผ ์๊ธฐ ์ํด์๋ user stack์ ์คํ ํฌ์ธํฐ(= rsp)๋ฅผ ๋จผ์ ์์๋ด์ผ ํ๋ค.
user program(User Mode)์์ ๋ฐ์ํ page fault๋ ์ธ์๋ก ์ ๋ฌ๋ intr_frame์ ํตํด rsp๋ก ๊ฐ์ ธ์ฌ ์ ์์ง๋ง,
syscall(Kernel Mode)์์ ๋ฐ์ํ page fault๋ ์ธ์๋ก ์ ๋ฌ๋ intr_frame->rsp๊ฐ user stack์ ์คํ ํฌ์ธํฐ๊ฐ ์๋ kernel stack์ ์คํ ํฌ์ธํฐ๋ฅผ ์ป๊ฒ ๋๋ค.
๋ฐ๋ผ์ kernel mode์์๋ user stack์ rsp๋ฅผ ์ป๊ธฐ ์ํด์ user mode->kernel mode ์ด๊ธฐ ์ ํ ์(= syscall_handler()) struct thread์ ์ ์ฅํด ์ ๋ฌํ๋ ๋ฑ์ ๋ฐฉ๋ฒ์ ์ค๋นํด์ผ ํ๋ค.
1. thread ๊ตฌ์กฐ์ฒด์ rsp ๋ฉค๋ฒ๋ณ์ ์ถ๊ฐ
struct thread
{
...
#ifdef VM
struct supplemental_page_table spt;
void *rsp; // ์คํ ํฌ์ธํฐ ์ ์ฅ์ ์ํ ๋ฉค๋ฒ๋ณ์
...
}
2. syscall_handler()์์ rsp ์ ์ฅ
void syscall_handler(struct intr_frame *f UNUSED)
{
...
/* ์ปค๋ ๋ชจ๋๋ก ์ ํ๋ ๋, ์ฆ ์์คํ
์ฝ์ด ํธ์ถ๋ ๋ ์คํ ํฌ์ธํฐ ์ ์ฅ */
#ifdef VM
thread_current()->rsp = f->rsp;
...
}
์ด์ ์ด rsp๋ฅผ ํ์ฉํด ํ๋ณํ ์ ์์ ๊ฒ์ด๋ค.
๊ทธ๋ ๋ค๋ฉด ์กฐ๊ฑด๋ฌธ์ ์๋์ฒ๋ผ ์ ์ฉํ๋ฉด ๋ ๊น?
void *rsp = f->rsp;
if (!user)
{
rsp = thread_current()->rsp;
}
/* stack growth๋ก ์ฒ๋ฆฌํ ์ ์๋ ๊ฒฝ์ฐ */
if (USER_STACK - (1 << 20) <= rsp && rsp <= addr && addr <= USER_STACK)
{
vm_stack_growth(addr);
}
์๋, ํ ๊ฐ์ง ๊ณ ๋ คํ ๊ฒฝ์ฐ๊ฐ ๋ ์๋ค.
rsp๋ณด๋ค ๋ฎ์ ์ฃผ์์ ์ ๊ทผํ๋๋ผ๋ stack growth๋ก ํด๊ฒฐํ ์ ์๋ ๊ฒฝ์ฐ๊ฐ ์๋ค.
x86-64์ PUSH ๋ช
๋ น์ด๋ค.
PUSH ๋ช ๋ น์ ์คํ ํฌ์ธํฐ๋ฅผ ์กฐ์ ํ๊ธฐ ์ ์ ์ ๊ทผ ๊ถํ์ ํ์ธํ๊ธฐ ๋๋ฌธ์, ์คํ ํฌ์ธํฐ๋ก๋ถํฐ 8๋ฐ์ดํธ ์๋์์ page fault๋ฅผ ๋ฐ์์ํฌ ์ ์๋ค.
rsp - 8byte์ธ ์ด์ ? ๐ค
์คํ์ ๊ฐ์ PUSHํ ๋, 64bit ์์คํ ์์๋ 8byte ๋จ์๋ก ๋ฐ์ดํฐ๋ฅผ pushํ๊ธฐ ๋๋ฌธ์ด๋ค. (register = rax)
๋ฌผ๋ก 32bit ํ๊ฒฝ์ด๋ผ๋ฉด - 4byte์ด๋ค. (register = eax)
๊ทธ๋ฌ๋ ๊ฐ์์ฃผ์๊ฐ rsp-8 ์ ๊ฐ๋ฆฌํค๋ ๊ฒฝ์ฐ๋ stack growth๋ก page fault๋ฅผ ์ฒ๋ฆฌํ ์ ์๋ค.
์ต์ข
์กฐ๊ฑด๋ฌธ์ ์๋์ ๊ฐ๋ค.
bool vm_try_handle_fault(struct intr_frame *f UNUSED, void *addr UNUSED, bool user UNUSED, bool write UNUSED, bool not_present UNUSED)
{
...
/* ์ ๊ทผํ ๋ฉ๋ชจ๋ฆฌ์ ๋ฌผ๋ฆฌ ํ๋ ์์ด ์กด์ฌํ์ง ์๋ ๊ฒฝ์ฐ, not_present = true */
if (not_present)
{
void *rsp = f->rsp;
if (!user)
{
rsp = thread_current()->rsp;
}
/* stack growth๋ก ์ฒ๋ฆฌํ ์ ์๋ ๊ฒฝ์ฐ */
if (USER_STACK - (1 << 20) <= rsp && rsp <= addr && addr <= USER_STACK)
{
vm_stack_growth(addr);
}else if(USER_STACK - (1 << 20) <= rsp - 8 && rsp - 8 == addr && addr <= USER_STACK){
vm_stack_growth(addr);
}
...
}
return false;
}
ํด๋น ์กฐ๊ฑด๋ค์ ์๋์ ๊ฐ์ด ์ ๋ฆฌํ๋ค.
์ง๊ธ๊น์ง stack growth๋ก ํ์ด์ง ํดํธ๋ฅผ ์ฒ๋ฆฌํ ์ ์๋ ๊ฒฝ์ฐ๋ฅผ ๋ฐ์ ธ ํธ์ถํ๋ ๊ฒ๊น์ง ๊ตฌํํ๋ค.
์ด์ ํด๋น ํจ์๋ง ๊ตฌํํ๋ฉด ์ด๋ฒ ํํธ์ ๊ณผ์ ๋ฅผ ์๋ฃํ๋ค.
vm_stack_growth() ๊ตฌํ์ ์ฌ์ค ๊ฐ๋จํ๋ค.
์ฌ๋ฐ๋ฅธ ์์น์ ์ ํ์ด์ง๋ฅผ ํ ๋นํ๊ธฐ๋ง ํ๋ฉด ๋๋ค. ๊ทธ๋ ๋ค๋ฉด ์ ๊ทผํ๋ ์ฃผ์๊ฐ faulted ์ฃผ์์์ ์ ํจํ ์ฃผ์๊ฐ ๋์ด page fault๋ฅผ ์ฒ๋ฆฌํ ์ ์๋ค. ์ด๋ฅผ ์ํด ์๊ฐํด์ผ ํ ์ ์ด ๋ ๊ฐ์ง ์๋ค.
1) ์ด๋ค ํ์
์ ํ์ด์ง๋ฅผ ํ ๋นํด์ผ ํ ๊น?
2) ์ด๋ ์์น์์ ํ์ด์ง๋ฅผ ํ ๋นํด์ผ ํ ๊น?
์ผ๋จ ์ฒซ ๋ฒ์งธ๋, ์ด์ ํํธ์ธ anon ํํธ์ ๋ต์ด ์๋ค.
anonymous page๋ ์คํ์ด๋ ํ ์์ญ์์ ์ฌ์ฉ๋๋ค๊ณ ํ๋ค.
์์ง ๋ฐ์ดํฐ๊ฐ ๋งคํ๋์ง ์์ ์ด๊ธฐํ๋ ํ์ด์ง์ฌ์ผ ํ๊ธฐ ๋๋ฌธ์ด๋ค.
๋ ๋ฒ์งธ๋ ํ์ด์ง ๊ฒฝ๊ณ ์ฃผ์ ์์น์์ ํ ๋นํด์ผ ํ๋ค.
๋ฉ๋ชจ๋ฆฌ๋ ํ์ด์ง ๋จ์๋ก ๊ด๋ฆฌ๋๊ธฐ ๋๋ฌธ์ด๋ค.
๊ทธ๋ ๋ค๋ฉด ์ด๋ฅผ ํ ๋๋ก vm_stack_growth()๋ฅผ ๊ตฌํํด๋ณด์.
static void
vm_stack_growth(void *addr UNUSED)
{
/* addr์ PGSIZE ๋งํผ ๋ด๋ ค anon page๋ฅผ ํ ๋น */
vm_alloc_page(VM_ANON | VM_MARKER_0, pg_round_down(addr), 1);
}
[์ต์ข ์ ๋ฆฌํ์๋ฉด]
1. page_fault ๋ฐ์
2. vm_try_handle_fault() ํธ์ถ
3. stack growth๋ก ํด๊ฒฐํ ์ ์๋์ง ํ๋ณ
4. ์๋ค๋ฉด stack growth๋ก ์ ํ์ด์ง ํ ๋น
5. spt์์ ํด๋น ๊ฐ์ ์ฃผ์์ ํด๋นํ๋ ํ์ด์ง๋ฅผ ๋ฐํ
6. ํด๋น ํ์ด์ง๋ก vm_do_claim_page()๋ฅผ ํธ์ถ
7. ๋ฌผ๋ฆฌ ํ๋ ์์ ํ ๋น๋ฐ๊ณ ๋งคํํจ์ผ๋ก์จ page fault ์ฒ๋ฆฌ
+) ์ถ๊ฐ๋ก ์ ๋ฆฌํ ๊ฒ
: pg_round_down()์ด๋ ๊ฒ ๊ทธ๋ฅ ํ์ด์ง ๊ฒฝ๊ณ๋ก ๋ด๋ฆผํ๋ ๋งคํฌ๋ก๋ผ๊ณ ๋ง ์ดํดํ์๋๋ฐ,
๋ค๋ฅธ ๋๋ฃ์ ๋ฐํ๋ฅผ ๋ฃ๊ณ ๋ ์์ธํ ์๊ฒ๋ ์ ์ด ์๋ค.
pg_round_down()? ๐ค
๊ฐ์์ฃผ์๋ PN(ํ์ด์ง ๋ฒํธ)+offset์ผ๋ก ์ด๋ฃจ์ด์ ธ ์๋ค.
ํ์ด์ง ๋ฒํธ๋ ํ์ด์ง ํฌ๊ธฐ์ ๋ฐฐ์์ ๊ฐ๊ณ , ๊ฒฐ๊ตญ ํ์ด์ง ๊ฒฝ๊ณ๋ ํ์ด์ง ๋ฒํธ๋ ๋ง์ฐฌ๊ฐ์ง๋ค.
offset์ ํด๋น ํ์ด์ง ๋ด์ ์ ํํ ์์น๋ฅผ ์ง์ ํ๊ธฐ ์ํ ๋ถ๋ถ์ด๋ค.
๊ทธ๋ฌ๋ pg_round_down์ offset์ ๋ผ์ด๋ด ํ์ด์ง ๋ฒํธ๋ฅผ ์ป์ด๋ด๋ ์์ ์ ํ๋ ๊ฒ์ด๋ค.
pg_round_down ๋งคํฌ๋ก๋ฅผ ๋ณด๋ฉด ๋ ์์ธํ ์ ์ ์๋ค./* Page offset bits (0:12). */ #define PGMASK BITMASK(PGSHIFT, PGBITS) /* Round down to nearest page boundary. */ #define pg_round_down(va) (void *) ((uint64_t) (va) & ~PGMASK)
์ด๋ ๊ฒ stack_growth ํํธ๊น์ง ์๋ฃํ๋ค.
stack ์ฑ์ฅ๊ณผ ์ฐ๊ด๋ tc๋ค์ด ํต๊ณผํ๋ ๊ฑธ ํ์ธํ ์ ์์๋ค.
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
pass tests/vm/pt-grow-stack
pass tests/vm/pt-grow-bad
pass 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
pass 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
pass tests/vm/mmap-ro
FAIL tests/vm/mmap-exit
FAIL tests/vm/mmap-shuffle
FAIL 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
FAIL tests/vm/mmap-bad-fd2
FAIL tests/vm/mmap-bad-fd3
FAIL 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
FAIL tests/filesys/base/syn-read
pass tests/filesys/base/syn-remove
FAIL 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
35 of 141 tests failed.
- strcut thread
- syscall_handler()
- vm_try_handle_fault()
- vm_stack_growth()