GitBOOK 정리다
프로젝트 2까지는 스택이 USER_STACK
단일 페이지 였으니
이제 이를 추가 할당해줘야 한다는 내용이다
유의점은 추가 페이지 할당은 스택 접근일때에만 유효하다는 거다
즉, 이걸 구분할 휴리스틱(대강 구분법)을 고안하란다
기본적으로 스택 포인터 아래 쓰기는 버그다
그치만, PUSH
명령은 스택 포인터 아래 8바이트에서 페이지 폴트를 일으킬 수 있고 이게 정상동작이라고 한다
이게 무슨 말이냐?
기본적으로 스택은 아래로 성장하며 현재 스택 포인터 RSP
는 스택 꼭대기를 가리킨다
프로그램은 스택을 쓸때 RSP
를 줄여 공간을 만들고 그 영역에 값을 저장하기에
그 아래에 쓰면 OS가 언제든 인터럽트/시그널을 통해 그 자리(스택)에 커널/시그널 프레임을 써넣어 충돌 날 수 있기에 버그라고 본다
단, PUSH
는 예외다
x86-64에서 push rax
같은 명령은
RSP-8
로 접근 권한 체크
접근 가능시 RSP := RSP - 8
하고 값을 저장
이런식으로 진행되기에 메모리 접근 확인이 RSP
를 줄이기 전에 RSP-8
로 수행된다
그렇기에 RPS
로부터 8바이트 아래의 페이지 폴트는 정상 동작으로 봐야 한다는 거다
즉, 스택 성장 휴리스틱은 RSP
바로 아래 범위의 폴트를 정상적인 스택 접근으로 인정하기를 원한다는 것이다
syscall_handler()
나 page_fault()
시 전달되는 struct intr_frame
의 rsp
멤버에서 이를 가져올 수 있다
스택 성장을 위해 RSP와 폴트 난 주소 위치 관계를 파악해야 하는데 페이지 폴트가 커널모드에서 나버리면
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);
페이지 폴트 예외 처리할 때 호출된다
함수에서 페이지 폴트가 스택 성장의 유효한 경우인지 확인한다
스택성장으로 처리가능할 경우vm_stack_growth
호출
void vm_stack_growth (void *addr);
addr
이 더 이상 폴트 주소가 되지 않도록 익명 페이지 할당해 스택 크기 늘린다
할당 처리할 떄addr
을PGSIZE
로 내려야 한다(round down
)
이거 다 하면 스택 성장 테스트 케이스 통과다