
Stack Growth #
더보기
- 지난 프로젝트에서, 스택은
USER_STACK에서 시작하는 단일 페이지였고, 프로그램의 실행은 페이지 크기로 제한되었다. 지금부터는 스택이 현재 크기를 초과하면, 필요에 따라 추가 페이지를 할당한다. - 스택 접근으로 "보이는" 경우에만 추가 페이지를 할당한다. 스택 접근과 다른 접근을 구별하는 휴리스틱을 고안해야 한다.
- 유저 프로그램이 스택 페인터 아래에 스택에 데이터를 쓸 경우(스택의 top을 넘어서 쓰는 경우) 버그가 발생한다.
- 일반적인 실제 OS는 언제든지 프로세스를 중단시켜 "신호"를 전달하고, 이 신호가 스택의 데이터를 수정하기 때문이다.
- 그러나 x86-64 PUSH 명령어는 스택 포인터를 조정하기 전에 접근 권한을 확인하므로, 스택 포인터 아래 8바이트에서 페이지 폴트가 발생할 수 있다.
- 유저 프로그램의 스택 포인터의 현재 값을 얻을 수 있어야 한다.
- 유저 프로그램에서 생성된 시스템 콜이나 페이지 폴트 내에서, 각각
syscall_handler()나page_falut()에서 전달된struct intr_frame의rsp멤버에서 해당 값을 가져올 수 있다. - 페이지 폴트를 사용하여 잘못된 메모리 액세스를 감지하는 경우, 커널에서 페이지 폴트가 발생하는 다른 경우를 처리해야 한다.
- 프로세서는 예외로 인해 유저 모드에서 커널 모드로 전환될 때만 스택 포인터를 저장하므로,
page_fault()에서 전달된struct intr_frame에서rsp를 읽는 것은 유저 스택 포인터가 아닌 정의되지 않은 값을 가지게 된다. - 유저 모드에서 커널 모드로의 초기 전환할 때
struct thread에rsp를 저장하는 것과 같은 다른 방법을 마련해야 한다.
- 유저 프로그램에서 생성된 시스템 콜이나 페이지 폴트 내에서, 각각
스택 성장 기능을 구현해야 한다: 먼저 스택 성장을 식별하기 위해 vm.c에서 vm_try_handle_fault를 수정해야 한다. 스택 성장을 식별한 뒤에는 스택을 성장시키기 위해 vm_stack_growth를 구현하고 호출해야 한다.
bool vm_try_handle_fault (struct intr_frame *f, void *addr, bool user, bool write, bool not_present);
- 페이지 폴트 예외 처리 과정에서
exception.c의page_fault에서 호출된다.- 해당 페이지 폴트가 스택 성장에 있어 유효한 경우인지 아닌지를 확인해야 한다.
- 페이지 폴트가 스택 성장으로 처리될 수 있는 것으로 확인되면, 폴트된 주소에
vm_stack_growth를 호출한다.
void vm_stack_growth (void *addr);
- 하나 이상의 anonymous pages를 할당함으로써 스택 크기를 증가시킨다.
addr은 더 이상 폴트된 주소가 아니게 된다.- 할당할 때
addr을 PGSIZE로 내림해야 한다.
대부분의 OS에서 스택 크기는 절대적인 제한을 가지고 있다. 이 프로젝트의 경우, 스택 크기를 최대 1MB로 제한해야 한다. 이제 모든 stack-growth 테스트 케이스를 pass해야 한다.
메모리 구조 (다시) 그리기

'Krafton Jungle > 5. PintOS' 카테고리의 다른 글
| [PintOS 4주차] Day 7 (0) | 2025.06.04 |
|---|---|
| [PintOS 4주차] Day 6 (0) | 2025.06.03 |
| [PintOS 4주차] Day 3 (0) | 2025.05.31 |
| [PintOS 4주차] Day 2 (4) | 2025.05.30 |
| [PintOS 4주차] Day 0-1 (0) | 2025.05.28 |