Krafton Jungle/5. PintOS

[PintOS 4주차] Day 4-5

munsik22 2025. 6. 2. 10:46

Stack Growth #

더보기
  • 지난 프로젝트에서, 스택은 USER_STACK에서 시작하는 단일 페이지였고, 프로그램의 실행은 페이지 크기로 제한되었다. 지금부터는 스택이 현재 크기를 초과하면, 필요에 따라 추가 페이지를 할당한다.
  • 스택 접근으로 "보이는" 경우에만 추가 페이지를 할당한다. 스택 접근과 다른 접근을 구별하는 휴리스틱을 고안해야 한다.
  • 유저 프로그램이 스택 페인터 아래에 스택에 데이터를 쓸 경우(스택의 top을 넘어서 쓰는 경우) 버그가 발생한다.
    • 일반적인 실제 OS는 언제든지 프로세스를 중단시켜 "신호"를 전달하고, 이 신호가 스택의 데이터를 수정하기 때문이다.
    • 그러나 x86-64 PUSH 명령어는 스택 포인터를 조정하기 전에 접근 권한을 확인하므로, 스택 포인터 아래 8바이트에서 페이지 폴트가 발생할 수 있다.
  • 유저 프로그램의 스택 포인터의 현재 값을 얻을 수 있어야 한다.
    • 유저 프로그램에서 생성된 시스템 콜이나 페이지 폴트 내에서, 각각 syscall_handler()page_falut()에서 전달된 struct intr_framersp 멤버에서 해당 값을 가져올 수 있다.
    • 페이지 폴트를 사용하여 잘못된 메모리 액세스를 감지하는 경우, 커널에서 페이지 폴트가 발생하는 다른 경우를 처리해야 한다.
    • 프로세서는 예외로 인해 유저 모드에서 커널 모드로 전환될 때만 스택 포인터를 저장하므로, page_fault()에서 전달된 struct intr_frame에서 rsp를 읽는 것은 유저 스택 포인터가 아닌 정의되지 않은 값을 가지게 된다.
    • 유저 모드에서 커널 모드로의 초기 전환할 때 struct threadrsp를 저장하는 것과 같은 다른 방법을 마련해야 한다.

스택 성장 기능을 구현해야 한다: 먼저 스택 성장을 식별하기 위해 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.cpage_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