https://velog.io/@yerimii11/PintOS-Project-3-Stack-Growth 2022년 1월 27일에 작성된 게시글 아카이브입니다. (사유: 블로그이전)
- Stack Growth
프로젝트 2에서 스택은 USER_STAK부터 시작하는 단일 페이지였으며, 프로그램의 실행은 이 크기로 제한되었습니다. 이제 스택이 현재 크기를 초과하여 커지면, 필요에 따라 추가 페이지를 할당합니다.
추가 페이지가 스택 액세스로 "표시(appear)"되는 경우에만 페이지를 할당합니다. 스택 액세스를 다른 액세스와 구별하는 경험적 접근 방법(heuristic)을 구상합니다.
사용자 프로그램들이 스택 포인터 아래의 스택에 쓸 경우 버그가 발생하는데, 그 이유는 전형적인 실제 OS들이 스택의 데이터를 수정하는 "신호(signal)"를 전달하기 위해 프로세스를 언제든지 중단할 수 있기 때문입니다. 그러나 x86-64 PUSH 명령은 스택 포인터를 조정하기 전에 액세스 권한을 확인하므로 스택 포인터보다 8바이트 아래에 페이지 오류가 발생할 수 있습니다.
사용자 프로그램의 스택 포인터의 현재 값을 얻을 수 있어야 합니다. 시스템 호출 또는 사용자 프로그램에 의해 생성된 페이지 장애 내에서 syscall_handler() 또는 page_fault()로 전달된 구조의 rsp 멤버에서 각각 이를 검색할 수 있습니다. 잘못된 메모리 액세스를 탐지하기 위해 페이지 폴트를 의존(사용)하는 경우, 커널에서 페이지 폴트가 발생하는 다른 경우를 처리해야 합니다.
예외로 인해 사용자 모드에서 커널 모드로 전환되는 경우에만 프로세서가 스택 포인터를 저장하기 때문에, page_fault()에 전달된 struct intr_frame에서 rsp를 읽으면 사용자 스택 포인터가 아닌 정의되지 않은 값이 생성됩니다. 사용자 모드에서 커널 모드로 처음 전환할 때 rsp를 struct thread에 저장하는 것과 같은 다른 방법을 준비해야 합니다.
→ vm_try_handle_fault : void *rsp_stack = is_kernel_vaddr(f->rsp) ? thread_current()->rsp_stack : f->rsp;
.
stack growth(스택 증가) 기능을 구현합니다. 이를 구현하려면 먼저 vm/vm.c에서 vm_try_handle_fault를 수정하여 스택 증가를 식별합니다.
스택 증가를 식별한 후에는 vm/vm.c의 vm_stack_growth를 호출하여 스택을 확장해야 합니다. vm_stack_growth를 구현하세요.
- 구현1.
bool vm_try_handle_fault (struct intr_frame *f, void *addr,
bool user, bool write, bool not_present);
이 함수는 페이지 폴트 예외를 처리하는 동안 userprog/exception.c에서 page_fault로 호출됩니다.
이 함수에서는 페이지 폴트가 stack growth에 유효한 경우인지 아닌지(이 페이지폴트가 stack growth와 관련된 페이지 폴트인지) 확인해야 합니다. stack growth가 페이지폴트를 처리할 수 있음을 확인한 경우, 페이지 폴트가 발생한 주소로 vm_stack_growth를 호출합니다.
- 코드
// [exception.c]
/* 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;
/* TODO: Validate the fault */
/* TODO: Your code goes here */
// return vm_do_claim_page (page);
// Step 1. Locate the page that faulted in the supplemental page table
void * fpage_uvaddr = pg_round_down(addr); // round down to nearest PGSIZE
// void * fpage_uvaddr = (uint64_t)addr - ((uint64_t)addr%PGSIZE); // round down to nearest PGSIZE
struct page *fpage = spt_find_page(spt, fpage_uvaddr);
// Invalid access - Not in SPT (stack growth or abort) / kernel vaddr / write request to read-only page
if(is_kernel_vaddr(addr)){
return false;
}
else if (fpage == NULL){
void *rsp = user ? f->rsp : thread_current()->rsp; // a page fault occurs in the kernel
const int GROWTH_LIMIT = 32; // heuristic
const int STACK_LIMIT = USER_STACK - (1<<20); // 1MB size limit on stack
// Check stack size max limit and stack growth request heuristically
if((uint64_t)addr > STACK_LIMIT && USER_STACK > (uint64_t)addr && (uint64_t)addr > (uint64_t)rsp - GROWTH_LIMIT){
vm_stack_growth (fpage_uvaddr);
fpage = spt_find_page(spt, fpage_uvaddr);
}
else{
exit(-1); // mmap-unmap
//return false;
}
}
else if(write && !fpage->writable){
exit(-1); // mmap-ro
// return false;
}
ASSERT(fpage != NULL)
// Step 2~4.
bool gotFrame = vm_do_claim_page (fpage);
// if (gotFrame)
// list_push_back(&frame_table, &fpage->frame->elem);
return gotFrame;
}
- 추가
// [include>threads>thread.h]
// struct thread의 #ifdef VM - #endif 밑에 추가
// Project 3-2 stack growth
uint64_t rsp; // a page fault occurs in the kernel
- 구현2.
void vm_stack_growth (void *addr);
addr가 더 이상 오류 주소가 되지 않도록 하나 이상의 익명 페이지를 할당하여 스택 크기를 늘립니다. 할당을 처리할 때 PGSIZE 로 addr를 내림해야 합니다.
대부분의 OS들은 스택 크기에 대한 절대적인 제한을 부과합니다. 일부 OS는 예를 들어 많은 Unix 시스템에서 ulimit 명령을 사용하여 사용자가 조정할 수 있도록 제한을 설정합니다. 많은 GNU/Linux 시스템에서 기본 제한은 8MB입니다. 이 프로젝트의 경우 스택 크기를 최대 1MB로 제한해야 합니다.
- 코드
/* Growing the stack. */
static void
vm_stack_growth (void *addr UNUSED) {
vm_alloc_page(VM_ANON | VM_MARKER_0, addr, true); // Create uninit page for stack; will become anon page
//bool success = vm_claim_page(addr);
}
이제 모든 stack-growth의 테스트 케이스를 통과해야 합니다.
- 수정사항
container 추가, [process.c]에 setup_stack 함수 #ifdef VM 부분 맨 아래에 구현 안해놨던 것 구현해줌.
syscall.c의 check_address등 바꿔줘야 함
- 여기까지 결과 (40 of 141 tests failed.)
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
FAIL tests/userprog/fork-close
FAIL 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
**FAIL 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
FAIL tests/vm/pt-grow-stk-sc**
pass tests/vm/page-linear
**FAIL tests/vm/page-parallel
FAIL 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
FAIL tests/vm/mmap-ro
FAIL tests/vm/mmap-exit
FAIL tests/vm/mmap-shuffle**
pass 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
pass tests/vm/mmap-bad-fd2
pass tests/vm/mmap-bad-fd3
pass 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**
40 of 141 tests failed.
'SW Jungle [예림] > PintOS' 카테고리의 다른 글
[PintOS] Project 3 - Swap In/Out (0) | 2022.10.24 |
---|---|
[PintOS] Project 3 - Memory Mapped Files (0) | 2022.10.24 |
[PintOS] Project 3 - Anonymous Page (2) (0) | 2022.10.24 |
[PintOS] Project 3 - Anonymous Page (1) (0) | 2022.10.24 |
[PintOS] Project 3 - Memory Management (0) | 2022.10.24 |
댓글