프로젝트 2에서 스택은 USER_STACK에서 시작하는 단일 페이지였고, 프로그램의 실행은 이 크기로 제한되었습니다. 이제 스택이 현재 크기를 넘어서 증가하면, 필요에 따라 추가 페이지를 할당합니다.
스택 접근으로 "보이는" 경우에만 추가 페이지를 할당하세요. 스택 접근과 다른 접근을 구별하려고 시도하는 휴리스틱을 고안하세요.
사용자 프로그램이 스택 포인터 아래의 스택에 쓰는 것은 버그입니다. 왜냐하면 일반적인 실제 OS는 언제든지 프로세스를 중단하여 "신호"를 전달할 수 있고, 이는 스택의 데이터를 수정하기 때문입니다. 그러나 x86-64 PUSH 명령어는 스택 포인터를 조정하기 전에 접근 권한을 확인하므로, 스택 포인터 아래 8바이트에서 페이지 폴트를 발생시킬 수 있습니다.
사용자 프로그램의 스택 포인터의 현재 값을 얻을 수 있어야 합니다. 시스템 콜이나 사용자 프로그램에 의해 생성된 페이지 폴트 내에서, 각각 syscall_handler()나 page_fault()에 전달된 struct intr_frame의 rsp 멤버에서 이를 검색할 수 있습니다. 잘못된 메모리 접근을 감지하기 위해 페이지 폴트에 의존하는 경우, 커널에서 페이지 폴트가 발생하는 다른 경우를 처리해야 합니다. 프로세서는 예외가 사용자 모드에서 커널 모드로 전환을 일으킬 때만 스택 포인터를 저장하므로, page_fault()에 전달된 struct intr_frame에서 rsp를 읽는 것은 사용자 스택 포인터가 아닌 정의되지 않은 값을 생성합니다. 사용자에서 커널 모드로의 초기 전환 시 rsp를 struct thread에 저장하는 것과 같은 다른 방법을 마련해야 합니다.
이를 구현하려면 먼저 vm/vm.c의 vm_try_handle_fault를 수정하여 스택 증가를 식별해야 합니다. 스택 증가를 식별한 후, vm/vm.c의 vm_stack_growth를 호출하여 스택을 증가시켜야 합니다. vm_stack_growth를 구현하세요.
bool vm_try_handle_fault (struct intr_frame *f, void *addr,
bool user, bool write, bool not_present);
이 함수는 페이지 폴트 예외를 처리하는 동안 userprog/exception.c의 page_fault에서 호출됩니다. 이 함수에서 페이지 폴트가 스택 증가에 유효한 경우인지 확인해야 합니다. 폴트가 스택 증가로 처리될 수 있음을 확인한 경우, 폴트된 주소로 vm_stack_growth를 호출하세요.
void vm_stack_growth (void *addr);
하나 이상의 익명 페이지를 할당하여 스택 크기를 증가시켜 addr이 더 이상 폴트된 주소가 아니도록 합니다. 할당을 처리할 때 addr을 PGSIZE로 내림하는 것을 확인하세요.
대부분의 OS는 스택 크기에 절대적인 제한을 부과합니다. 일부 OS는 제한을 사용자가 조정할 수 있게 만듭니다. 예를 들어 많은 Unix 시스템에서 ulimit 명령을 사용합니다. 많은 GNU/Linux 시스템에서 기본 제한은 8MB입니다. 이 프로젝트의 경우 스택 크기를 최대 1MB로 제한해야 합니다.
<aside> 🥕
이제 모든 스택 증가 테스트 케이스가 통과되어야 합니다.
</aside>