[TIL/06.09]PintOS VM - Stack Growth

CHO WanGiยท2025๋…„ 6์›” 9์ผ

KRAFTON JUNGLE 8th

๋ชฉ๋ก ๋ณด๊ธฐ
67/89

์ฐธ๊ณ  ์ž๋ฃŒ

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

  • ๐Ÿšจ ๋‘๋ฒˆ์งธ ๋งํฌ์ธ Kaist OS LAB(EE) ์ž๋ฃŒ๋Š” 64๋น„ํŠธ๊ฐ€ ์•„๋‹Œ 32๋น„ํŠธ ๊ธฐ์ค€์œผ๋กœ ์„œ์ˆ ๋˜์–ด ์žˆ์Œ

์š”๊ตฌ์‚ฌํ•ญ

ํ˜„์žฌ PintOS๋Š” ์Šคํƒ์˜ ํฌ๊ธฐ๊ฐ€ ๊ณ ์ •๋˜์–ด์žˆ๋‹ค.
์ด ์Šคํƒ์ด overflow๊ฐ€ ๋‚˜๊ฒŒ๋˜๋ฉด ํ•ด๋‹น Process๋ฅผ Kill ํ•˜๋Š”๋ฐ,
์ด๋•Œ Stack Access๋กœ ๋ณด์ธ๋‹ค๋ฉด ์Šคํƒ์„ ๋Š˜๋ ค์ฃผ์–ด์•ผ ํ•œ๋‹ค.

Stack ์˜์—ญ์˜ ๊ธฐ์ค€?

์œ„ KAIST ์ž๋ฃŒ๋Š” 32๋น„ํŠธ๋ผ esp ํฌ์ธํ„ฐ๋ผ๊ณ  ๋‚˜์™€์žˆ์œผ๋‚˜

You will need to be able to obtain the current value of the user program's stack pointer. Within a system call or a page fault generated by a user program, you can retrieve it from the rsp member of the struct intr_frame passed to syscall_handler() or page_fault(), respectively.

GitBook์— rsp ํฌ์ธํ„ฐ๊ฐ€ ์Šคํƒ ์˜์—ญ์— ์ ‘๊ทผ ํ•  ์ˆ˜ ์žˆ๋Š” ํฌ์ธํ„ฐ๋ผ๊ณ  ๋‚˜์™€์žˆ๋‹ค.

rsp๋Š” ์–ด๋””์„œ ์–ป์„๊นŒ?

Page fault ํ•ธ๋“ค๋Ÿฌ ํ•จ์ˆ˜์ธ vm_try_handle_fault ์— parameter๋กœ ๋“ค์–ด์˜ค๋Š” ์ธ์ž๋ฅผ ๋ณด์ž.
intr_frame์„ *f๋กœ ๋ฐ›๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.


intr_frame์„ ํ™•์ธํ•ด๋ณด๋ฉด uintptr_t rsp ๊ฐ€ ์žˆ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

๋”ฐ๋ผ์„œ ๋‹ค์‹œ vm_try_handle_fault ์—์„œ ๋ณด๋ฉด f->rsp ๋กœ rsp ํฌ์ธํ„ฐ์— ์ ‘๊ทผ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•„๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

์ปค๋„๋ชจ๋“œ ์ผ๋•Œ Page Fault?

์œ„์—์„œ ๋ณธ intr_frame์œผ๋กœ ์ ‘๊ทผํ•˜๋Š” f-> rsp๋Š” USER MODE์—์„œ ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์ด๊ณ ,
์‹œ์Šคํ…œ ์ฝœ์—์„œ๋„ Page Fault๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

  • read
    buffer์— ๋‹ด๊ธด ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด๋‚ด๋Š” Read ์‹œ์Šคํ…œ ์ฝœ์—์„œ,
    ์ด buffer๊ฐ€ ์†ํ•œ ํŽ˜์ด์ง€๊ฐ€ ์—†์–ด์„œ Page Fault๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
    ์ด๋•Œ f->rsp ๋กœ ์ ‘๊ทผ์‹œ Kernel Stack์— ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์ด ๋˜์–ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.
    ๋”ฐ๋ผ์„œ ๋ฏธ๋ฆฌ Stack Pointer๋ฅผ ์ €์žฅํ•ด๋†“๊ณ  ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค.

๋”ฐ๋ผ์„œ thread์˜ #ifdef ๋ถ€๋ถ„์— *rsp ํฌ์ธํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ๋ณ€์ˆ˜๋ฅผ ๋„ฃ์–ด์ฃผ์—ˆ๋‹ค.

Stack Growth๊ฐ€ ํ•„์š”ํ•œ ์ƒํ™ฉ์ด ์–ธ์ œ์ผ๊นŒ?

Most Oses impose some absolute limit on stack size. Some OSes make the limit user-adjustable, e.g. with the ulimit command on many Unix systems. On many GNU/Linux systems, the default limit is 8 MB. For this project, you should limit the stack size to be 1MB at maximum.

PintOS์˜ USER STACK์˜ ํฌ๊ธฐ๋Š” 1MB๋ผ๊ณ  ํ–ˆ๋‹ค.
์ด๋•Œ ์Šคํƒ์˜ TOP์„ ๊ฐ€๋ฆฌํ‚ค๋Š” rsp๋ณด๋‹ค ๋‚ฎ์€ ์ฃผ์†Œ๋กœ ์ ‘๊ทผํ•  ๋•Œ ์ด rsp๋ฅผ ์•„๋ž˜๋กœ ๋‚ด๋ ค์„œ
Stack ํ™•์žฅ์„ ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

๋”ฐ๋ผ์„œ USER_STACK ~ USER_STACK-1MB ์‚ฌ์ด์— ์ ‘๊ทผํ•ด์•ผํ•œ๋‹ค.

๋‹ค๋งŒ, ์—ฌ๊ธฐ์„œ ์ฃผ์˜ํ•  ์‚ฌํ•ญ์€ rsp๋ณด๋‹ค ๋†’์€ ์ฃผ์†Œ๊ฐ’์— ์ ‘๊ทผํ•œ ๊ฒฝ์šฐ์—๋งŒ ์‹คํ–‰ํ•ด์•ผํ•œ๋‹ค.
OS๊ฐ€ ์‹คํ–‰๋˜๋‹ค๊ฐ€ ํ”„๋กœ์„ธ์Šค๋ฅผ ์ค‘๋‹จ์‹œ, ์‹คํ–‰์ •๋ณด๋ฅผ ์Šคํƒ์— ์ €์žฅํ•œ๋‹ค.
์ด๋•Œ ์Šคํƒ ํฌ์ธํ„ฐ ์•„๋ž˜์— ๋ฐ์ดํ„ฐ๋ฅผ ์จ๋†“์•˜๋‹ค๋ฉด ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฎ์–ด ์”Œ์›Œ์ง€๋ฉฐ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋‹ค.

  • ์˜ˆ์™ธ์ƒํ™ฉ
    ๊ทธ๋ ‡์ง€๋งŒ rsp๋ณด๋‹ค ๋‚ฎ์€ ์ฃผ์†Œ์ธ rsp-8 ์— ์ ‘๊ทผํ–ˆ์„๋•Œ ์Šคํƒ์„ ๋Š˜๋ ค์ฃผ๋Š” ์ƒํ™ฉ์ด ์žˆ๋Š”๋ฐ ๋ฐ”๋กœ
    push ๋ช…๋ น์–ด ์‹คํ–‰ ์‹œ์ด๋‹ค.(ํ•จ์ˆ˜ ํ˜ธ์ถœ์‹œ ๋งค๊ฐœ๋ณ€์ˆ˜ stack ์ „๋‹ฌ, ์ง€์—ญ๋ณ€์ˆ˜ stack์— ํ• ๋‹น)

However, the x86-64 PUSH instruction checks access permissions before it adjusts the stack pointer, so it may cause a page fault 8 bytes below the stack pointer.

๋”ฐ๋ผ์„œ rsp-8 ์ฃผ์†Œ์—์„œ๋„ stack growth๋ฅผ ์ ์šฉํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

vm_try_handle_fault

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;
	void *MAX_STACK = (USER_STACK - (1 << 20));
	if (addr == NULL || is_kernel_vaddr(addr))
		return false;

	if (not_present)
	{
		/** Project 3-Stack Growth*/
		if (page == NULL)
		{
			// ํŽ˜์ด์ง€๊ฐ€ spt์— ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด, ์ฆ‰ ์•„์ง ํ•ด๋‹น ๊ฐ€์ƒ ์ฃผ์†Œ์— ๋Œ€ํ•œ ๋งคํ•‘์ด ์—†๋‹ค๋ฉด,

			void *rsp = user ? pg_round_down(f->rsp) : thread_current()->rsp;
			// ๋งŒ์•ฝ ์œ ์ € ๋ชจ๋“œ๋ผ๋ฉด ์œ ์ € ์Šคํƒ ํฌ์ธํ„ฐ(rsp)๋ฅผ ํ˜„์žฌ ์ธํ„ฐ๋ŸฝํŠธ ํ”„๋ ˆ์ž„์—์„œ ๊ฐ€์ ธ์˜ค๊ณ ,
			// ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด (์ปค๋„ ๋ชจ๋“œ์ผ ๊ฒฝ์šฐ) ํ˜„์žฌ ์Šค๋ ˆ๋“œ์— ์ €์žฅํ•ด๋‘” ์Šคํƒ ํฌ์ธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
			// ๋‹จ, ์œ ์ € ์Šคํƒ์€ ํŽ˜์ด์ง€ ๋‹จ์œ„๋กœ ํ• ๋‹น๋˜๊ธฐ ๋•Œ๋ฌธ์— rsp๋ฅผ ํŽ˜์ด์ง€ ํ•˜๋‹จ ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌํ•œ๋‹ค.

			if (MAX_STACK <= rsp - 8 && rsp - 8 == addr && addr <= USER_STACK)
			{
				// push ๋ช…๋ น์–ด ๋“ฑ์œผ๋กœ ์ธํ•ด rsp๋ณด๋‹ค ๋‚ฎ์€ ์ฃผ์†Œ์— ์“ฐ๊ธฐ๋ฅผ ์‹œ๋„ํ•œ ๊ฒฝ์šฐ
				// ์Šคํƒ ํ”„๋ ˆ์ž„ ํ‘ธ์‹œ ์ง์ „ ์ฃผ์†Œ ์ ‘๊ทผ์ธ ๊ฒฝ์šฐ (push ๋ช…๋ น์–ด ์งํ›„์— fault ๋‚˜๋Š” ์ƒํ™ฉ

				if (!vm_stack_growth(addr))
					return false;
			}
			else if (MAX_STACK <= rsp && rsp <= addr && addr <= USER_STACK)
			{
				//  rsp๋ณด๋‹ค ๋†’์€ ์ฃผ์†Œ์— ์ ‘๊ทผํ–ˆ์ง€๋งŒ ์—ฌ์ „ํžˆ ์Šคํƒ ์˜์—ญ์ธ ๊ฒฝ์šฐ
				// ์ผ๋ฐ˜์ ์ธ ์Šคํƒ ์‚ฌ์šฉ (์˜ˆ: ์ง€์—ญ ๋ณ€์ˆ˜ ํ• ๋‹น ๋“ฑ)์œผ๋กœ ์ธํ•œ ์ ‘๊ทผ์˜ ๊ฒฝ์šฐ

				if (!vm_stack_growth(addr))
					return false;
			}

			page = spt_find_page(spt, addr);
		}

		if (page == NULL || (write && !page->writable))
			return false;

		return vm_do_claim_page(page);
	}
	return false;
}

vm_stack_growth

/* Growing the stack. */
static bool
vm_stack_growth(void *addr UNUSED)
{
	void *va = pg_round_down(addr);
	if (vm_alloc_page_with_initializer(VM_ANON | VM_MARKER_0, va, true, NULL, NULL))
	{
		thread_current()->rsp = va;
		return vm_claim_page(va);
	}
	return false;
}

Result

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
pass tests/vm/pt-write-code2
pass tests/vm/pt-grow-stk-sc
  • ์ „์ฒด ๊ฒฐ๊ณผ
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
FAIL tests/userprog/fork-read
pass tests/userprog/fork-close
pass tests/userprog/fork-boundary
pass tests/userprog/exec-once
pass tests/userprog/exec-arg
FAIL 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
pass tests/vm/pt-write-code2
pass tests/vm/pt-grow-stk-sc
pass tests/vm/page-linear
FAIL 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
FAIL 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
38 of 141 tests failed.
profile
์ œ Velog์— ์˜ค์‹  ๋ชจ๋“  ๋ถ„๋“ค์ด ์ž‘๋”๋ผ๋„ ์ธ์‚ฌ์ดํŠธ๋ฅผ ์–ป์–ด๊ฐ€์…จ์œผ๋ฉด ์ข‹๊ฒ ์Šต๋‹ˆ๋‹ค :)

0๊ฐœ์˜ ๋Œ“๊ธ€