Always Be Wise

Project_3 : Virtual Memory - Stack Growth(1) 본문

카이스트 정글 - 프로젝트/Pintos

Project_3 : Virtual Memory - Stack Growth(1)

bewisesh91 2022. 1. 23. 15:21
728x90

현재 Pintos의 스택은 USER_STACK에서 시작하는 단일 페이지이다. 프로그램의 실행은 이 사이즈로 제한된다.

이제부터는 스택이 필요에 따라 추가 페이지를 할당받아 그 사이즈를 확장할 수 있도록 만들어야 한다.

 

추가 페이지가 스택 접근으로 표시된 경우에만 페이지를 할당해야 한다.

스택 액세스를 다른 액세스와 구별하는 경험적 방법을 고안해야 한다.

 

사용자 프로그램이 스택 포인터 아래에 위치한 스택에 무언가를 쓰려고 할 경우 버그가 발생한다.

그런데 x86-64의 PUSH 명령은 스택 포인터를 조정하기 전에 액세스 권한을 확인한다. 

따라서 스택 포인터 8바이트 아래에서 페이지 폴트가 발생할 수 있다.

 

사용자 프로그램의 스택 포인터 현재 값을 얻을 수 있어야 한다. 이는 사용자 프로그램에 의한 시스템 콜 또는 페이지 폴트 시,

syscall_handler( ) 또는 page_fault( )에 전달된 intr_frame 구조체의 rsp를 통해 확인할 수 있다. 

유효하지 않은 메모리 접근을 감지하기 위해 페이지 폴트를 사용하는 경우, 커널에서 페이지 폴트가 발생하는 상황을 처리해야 한다.

그런데 예외 처리로 인해 사용자 모드에서 커널 모드로 전환될 때만 프로세서가 스택 포인터를 저장하기 때문에,

page_fault( )에 전달된 intr_frame 구조체의 rsp는 정의되지 않은 값을 갖고 있다. 따라서 다른 방법을 마련해야 한다.

 

stack growth 관련 함수들을 구현해야 한다. 우선, stack growth를 식별하기 위해 vm/vm.c에 있는 vm_try_handle_fault( ) 함수를

수정해야 한다. stack growth를 식별한 이후에는 vm/vm.c에 있는 vm_stack_growth( ) 함수를 호출하여 스택을 확장해야 한다.

bool vm_try_handle_fault (struct intr_frame *f, void *addr, bool user, bool write, bool not_present);

vm_try_handle_fault( ) 함수는 페이지 폴트 예외 처리 시, userprog/exception.c의 page_falut( ) 함수에서 호출된다.

해당 페이지 폴트가 stack growth를 통해 해결될 수 있는 경우, vm_stack_growth( ) 함수를 호출한다.

void vm_stack_growth (void *addr);

페이지 폴트가 발생한 주소를 인자로 하여 vm_stack_growth( ) 함수를 호출하면,

하나 이상의 익명 페이지를 할당하여 해당 주소에서 더 이상 페이지 폴트가 발생하지 않도록 스택 사이즈를 확장한다.

할당을 처리할 때, PGSIZE로 주소를 round down 해야 한다.

 

대부분의 OS는 스택 사이즈에 절대적인 제한을 두고 있다.

일부 OS는 ulimit 명령을 사용하여 해당 제한을 사용자가 조정할 수 있도록 한다.

대부분의 GNU/Linux 시스템에서 기본 제한은 8 MB이다. Pintos에서는 1 MB로 제한해야 한다.

 

 

 

Comments