bool
vm_try_handle_fault (struct intr_frame *f UNUSED, void *addr,
bool user, bool write, bool not_present) {
struct thread *curr = thread_current ();
struct supplemental_page_table *spt = &curr->spt;
/* Validate the fault */
if (is_kernel_vaddr (addr) && user) return false;
void *stack_bottom = pg_round_down (curr->rsp);
if (write && (stack_bottom - PGSIZE <= addr &&
(uintptr_t) addr < USER_STACK)) {
/* Allow stack growth writing below single PGSIZE range
* of current stack bottom inferred from stack pointer. */
vm_stack_growth (addr);
return true;
}
struct page* page = spt_find_page (spt, addr);
if (page == NULL) return false;
if (write && !not_present) return vm_handle_wp (page);
return vm_do_claim_page (page);
}
1) stack_bottom 설정
2) 확장 요청한 스택 사이즈 확인
3) 스택 확장시, page 크기 단위로 해주기
4) 확장한 page 할당받기
static void
vm_stack_growth (void *addr UNUSED) {
void *stack_bottom = pg_round_down (addr);
size_t req_stack_size = USER_STACK - (uintptr_t)stack_bottom;
if (req_stack_size > (1 << 20)) PANIC("Stack limit exceeded!\n"); // 최대 1MB
// Alloc page from tested region to previous claimed stack page.
void *growing_stack_bottom = stack_bottom;
while ((uintptr_t) growing_stack_bottom < USER_STACK &&
vm_alloc_page (VM_ANON | VM_MARKER_0, growing_stack_bottom, true)) {
growing_stack_bottom += PGSIZE;
};
vm_claim_page (stack_bottom); // Lazy load requested stack page only
}