sw사관학교정글/PintOS(KAIST's CS330 class)

[week11] PintOS - Project 3(Virtual Memory) : Stack growth

D cron 2022. 1. 26. 00:25

Project 3 : Stack growth 구현

무엇을 하는가?

project 2에서 stack은 USER_STACK부터 시작하는 단일 page였으며 프로그램의 실행은 이 크기로 제한되었다. 이제 stack이 현재 크기를 초과하면 필요에 따라 추가 page를 할당한다.

page fault가 발생했을 때, 이 page fault가 stack growth에 대한 page fault인 경우, stack을 키운다.

stack growth 기능 구현

먼저 syscall handler를 수정한다.

void
syscall_handler (struct intr_frame *f UNUSED) {
    #ifdef VM
        thread_current()->rsp_stack = f->rsp; 
    #endif
...
}

system call을 한 user process의 user stack pointer를 thread 구조체에 저장해둔다.

왜 저장해두냐면 만약 인터럽트 프레임의 rsp 멤버가 user stack을 가리키고 있다면 그냥 그 stack pointer를 사용하면 된다. 그러나 인터럽트 프레임의 rsp 멤버가 kernel stack을 가리키고 있을 수 있다. 이 때 우리는 user stack을 키우는 것이 목적이므로 저장해두었던 rsp를 사용할 것이다.

vm_try_handle_fault() 함수에서 vm_stack_growth를 호출한다.

/* Return true on success */
bool
vm_try_handle_fault (struct intr_frame *f UNUSED, void *addr UNUSED,
        bool user UNUSED, bool write UNUSED, bool not_present UNUSED) {
    struct supplemental_page_table *spt UNUSED = &thread_current ()->spt;
    // project 3
    // user space page fault여야 한다.
    if(is_kernel_vaddr(addr)){
        return false;
    }
    // stack pointer를 가져오는 방법(아까 thread 구조체에 저장했던 이유가 여기나옴)
    void *rsp_stack = is_kernel_vaddr(f->rsp) ? thread_current()->rsp_stack : f->rsp;
    if(not_present){
        if(!vm_claim_page(addr)){
            if(rsp_stack - 8 <= addr && USER_STACK - 0x100000 <= addr && addr <= USER_STACK){
                vm_stack_growth(thread_current()->stack_bottom - PGSIZE);
                return true;
            }
            return false;
        }
        else
            return true;
    }
    return false;
    // return vm_do_claim_page (page);
}

PintOS에서는 총 stack의 크기를 1MB(0x100000)로 제한하기 때문에 받아온 주소가 USER_STACK으로부터 1MB 사이에 있는지 확인할 필요가 있다.

stack growth를 하는 함수

/* Growing the stack. */
static void
vm_stack_growth (void *addr UNUSED) {
    if(vm_alloc_page(VM_ANON | VM_MARKER_0, addr, 1)){
        vm_claim_page(addr);
        thread_current()->stack_bottom -= PGSIZE;
    }
}

stack bottom보다 1page 아래에서 page를 하나 만든다. stack이니까 anon type의 page가 된다.