Always Be Wise

Project_3 : Virtual Memory - Stack Growth(2) 본문

카이스트 정글 - 프로젝트/Pintos

Project_3 : Virtual Memory - Stack Growth(2)

bewisesh91 2022. 1. 24. 14:53
728x90

사용자 가상 주소 공간에서 발생한 페이지 폴트 및 시스템 콜의 경우, syscall_handler( ) 또는 page_fault( )에 전달된 intr_frame 구조체의

rsp를 사용하면 된다. 그러나 커널에서 페이지 폴트가 발생하는 경우, 추가적인 처리가 필요하다. 현재는 예외 처리 시 사용자 모드에서

커널 모드로 전환될 때만 프로세서가 스택 포인터를 저장하고 있다. 따라서, 페이지 폴트나 시스템 콜 핸들러가 호출될 때, 아래와 같이

thread 구조체에 현재 유저 스택 포인터를 미리 저장할 수 있도록 만들어야 한다.

void syscall_handler (struct intr_frame *f UNUSED) {
	// TODO: Your implementation goes here.
	#ifdef VM
		thread_current()->rsp_stack = f->rsp; 
	#endif

	// 중략
}

Implement stack growth.

스택의 맨 밑(stack bottom) 보다 아래에 접근하면 페이지 폴트가 발생한다. 해당 페이지 폴트가 stack growth와 관련한 것인지 확인하고,

관련이 있다면 vm_stack_growth( ) 함수를 호출해 스택을 늘릴 수 있도록 해야 한다. 우선, vm_try_handle_fault( ) 함수를 수정해보자.

함수 내부에서 페이지 폴트가 발생한 가상 주소가 어디에 속하는지 확인하고, 스택 포인터를 가져온다.

그리고 페이지의 present bit를 확인하고, vm_claim_page( ) 함수를 호출한다. 해당 함수의 리턴 값이 false, 즉 페이지가 없을 경우,

페이지 폴트 발생 주소가 유저 스택 내에 있고, 스택 포인터보다 8바이트 아래에 있지 않으면 vm_stack_growth( ) 함수를 호출한다.

/* vm/vm.c */

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;
	struct page *page = NULL;
	/* TODO: Validate the fault */
	/* TODO: Your code goes here */
	/*--------------- PROJECT3: Virtual Memory ----------------*/
	/* 1. 유저 공간 페이지 폴트여야 한다. */
	if (is_kernel_vaddr(addr)){ 
		return false;
	}
	/* 2. 스택 포인터를 어떻게 가져올 것인지 -> 페이지 폴트가 커널 영역에서 났는지, 유저 영역에서 났는지(확실X) */
	void *rsp_stack = is_kernel_vaddr(f->rsp) ? thread_current()->rsp_stack : f->rsp;
	
    	/* 3. 페이지의 Present bit이 0이면 -> 메모리 상에 존재하지 않으면 메모리에 프레임을 올리고 프레임과 페이지를 매핑시켜준다. */
	if (not_present){
	        /* 4. spt에 없다. 페이지가 없다. spt_find_page가 실패했을 때 */ 
            if (!vm_claim_page(addr)){
                if (rsp_stack - 8 <= addr && USER_STACK - 0x100000 <= addr && addr <= USER_STACK){
                    /* 5. 페이지 폴트 발생 주소가 유저 스택 내에 있고, 스택 포인터보다 8바이트 밑에 있지 않으면 */
                    vm_stack_growth(thread_current()->stack_bottom - PGSIZE);
                    return true;
                }
                return false;
            }
            else
                return true;
        }
	return false;
	/*---------------------------------------------------------*/
}

vm_stack_growth( ) 함수는 스택의 맨 밑(stack bottom) 보다 PGSIZE 만큼 아래의 주소에서 페이지를 하나 만드낟.

이 페이지의 타입은 anon이어야 한다. 맨 처음 uninit 페이지를 만들고 spt에 넣은 후, vm_claim_page( ) 함수를 호출한다.

/* vm/vm.c */

static void vm_stack_growth(void *addr UNUSED){
	/*--------------- PROJECT3: Virtual Memory ----------------*/
	if(vm_alloc_page(VM_ANON | VM_MARKER_0, addr, 1)){
        vm_claim_page(addr);
        thread_current()->stack_bottom -= PGSIZE;
    	}
	/*---------------------------------------------------------*/
}
Comments