일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 그리디 알고리즘(Greedy Algorithm)
- 백준 21606번
- DFS & BFS
- 백준 1948번
- 동적 프로그래밍(Dynamic Programming)
- BFS
- 분할 정복(Divide and Conquer)
- 그래프(Graph)
- 백준 2812번
- 백준 2504번
- 백준 9012번
- 백준 1707번
- BFS(Breadth First Search)
- DFS
- 위상 정렬(Topological Sort)
- 스택(Stack)
- 이분 그래프(Bipartite Graph)
- 백준 18352번
- 이분 탐색(Binary Search)
- 위상 정렬(Topology Sort)
- 백준 10000번
- 플로이드 워셜 알고리즘(Floyd-Warshall Algorithm)
- 알고리즘 개념
- DFS(Depth First Search)
- 백준 2493번
- 백준 2261번
- 다익스트라 알고리즘(Dijkstra Algorithm)
- 트리(Tree)
- 큐(Queue)
- 백준 17608번
- Today
- Total
Always Be Wise
Project_3 : Virtual Memory - Stack Growth(2) 본문
사용자 가상 주소 공간에서 발생한 페이지 폴트 및 시스템 콜의 경우, 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;
}
/*---------------------------------------------------------*/
}
'카이스트 정글 - 프로젝트 > Pintos' 카테고리의 다른 글
Project_3 : Virtual Memory - Memory Mapped Files(2) (0) | 2022.01.24 |
---|---|
Project_3 : Virtual Memory - Memory Mapped Files(1) (0) | 2022.01.24 |
Project_3 : Virtual Memory - Stack Growth(1) (0) | 2022.01.23 |
Project_3 : Virtual Memory - Anonymous Page(2) (0) | 2022.01.22 |
Project_3 : Virtual Memory - Anonymous Page(1) (0) | 2022.01.21 |