익명 페이지
디스크 기반이 아닌 이미지?
이 프로젝트의 이 부분에서는 익명 페이지라고 불리는 디스크 기반이 아닌 이미지를 구현할 것입니다.
•
디스크 기반 O : 실행파일(.exe)에서 읽어옴
•
디스크 기반 X : 파일에서 안 읽어옴, 그냥 0으로 채움
백업 파일이나 장치가 없다?
익명 매핑은 백업 파일이나 장치가 없습니다. 명명된 파일 소스가 없기 때문에(파일 지원 페이지와는 달리) 익명이라고 불립니다.
// 파일 지원 페이지 (VM_FILE)
page_fault() → "program.exe의 0x500 위치에서 읽어와"
// 익명 페이지 (VM_ANON)
page_fault() → "파일 없으니까 그냥 0으로 채워"
C
복사
스택과 힙을 위해 사용
익명 페이지는 실행 파일에서 스택과 힙을 위해 사용됩니다.
// 스택
int main() {
int x = 10; // VM_ANON 페이지
}
// 힙
char *ptr = malloc(100); // VM_ANON 페이지
C
복사
결론
파일에서 읽을 필요 없이 그냥 0으로 채우면 되는 페이지(마치 스택 & 힙처럼)
•
파일 페이지 = 책에서 복사한 내용
•
익명 페이지 = 빈 노드(새 종이)
Page Initialization with Lazy Loading(지연 로딩을 통한 페이지 초기화)
# 페이지 초기화 플로우
1. 프로그램 시작
↓
2. vm_alloc_page_with_initializer() 호출
→ SPT에 페이지 정보만 등록 (물리 메모리 할당 X)
↓
3. 사용자 프로그램 실행 계속
↓
4. 페이지 접근 시도
↓
5. 페이지 폴트 발생!
↓
6. uninit_initialize() 호출
↓
7. anon_initializer() 실행 (익명 페이지인 경우) / file_backed_initializer() 실행(파일 지원 페이지인 경우)
↓
8. 물리 메모리 할당 & 0으로 채움
Markdown
복사
Lazy Loading for Executable(실행 파일의 지연 로딩)
언제 페이지를 실제로 로드할까?
•
프로젝트 2 : 프로그램 시작할 때(즉시)
•
프로젝트 3 : 실제로 사용할 때(지연)
VM_UNINIT(페이지 타입)
모든 페이지는 처음에 VM_UNINIT 페이지로 생성됩니다. 또한 초기화되지 않은 페이지를 위한 페이지 구조체인 include/vm/uninit.h의 struct uninit_page를 제공합니다. 초기화되지 않은 페이지를 생성, 초기화, 파괴하는 함수들은 include/vm/uninit.c에서 찾을 수 있습니다.
페이지 생명주기:
생성 → VM_UNINIT (대기 중) → 페이지 폴트 → VM_ANON or VM_FILE (실제 타입)
struct page {
const struct page_operations *operations;
void *va; /* Address in terms of user space */
struct frame *frame; /* Back reference for frame */
/* Your implementation */
/* Project_3 Memory Management */
struct hash_elem hash_elem;
/* Per-type data are binded into the union.
* Each function automatically detects the current union */
union {
struct uninit_page uninit; // <----- 여기 부분
struct anon_page anon;
struct file_page file;
#ifdef EFILESYS
struct page_cache page_cache;
#endif
};
};
C
복사
실행 흐름 예시
1. 프로그램 시작
userprog/process.c
static bool load_segment(struct file* file, off_t ofs, uint8_t* upage,
uint32_t read_bytes, uint32_t zero_bytes,
bool writable) {
// 이하 생략....
/* TODO: Set up aux to pass information to the lazy_load_segment. */
/* 실제 로딩을 하는건 아니고, 페이지 폴트 발생 시 로딩하도록 페이지만 등록 */
void* aux = NULL;
if (!vm_alloc_page_with_initializer(VM_ANON, // 타입
upage, // 가상주소
writable, // 쓸 수 있는지 여부
lazy_load_segment, // 나중에 호출할 함수
aux // 파일 정보(어디서 읽을지)
))
return false;
// 이하 생략....
}
C
복사
2. vm_alloc_page_with_initializer 내부
bool vm_alloc_page_with_initializer(enum vm_type type, void *upage,
bool writable, vm_initializer *init,
void *aux) {
ASSERT(VM_TYPE(type) != VM_UNINIT);
struct supplemental_page_table *spt = &thread_current()->spt;
if (spt_find_page(spt, upage) == NULL) {
/* TODO: Create the page, fetch the initializer according to the VM type,
* and then create "uninit" page struct by calling uninit_new. */
/* TODO: Insert the page into the spt. */
}
return false;
}
C
복사
TODO 주석에 의하면(우리가 구현해야함) :
1. 페이지 구조체 생성
2. VM_UNINIT 타입의 페이지로 설정
3. SPT에 등록
이 시점에서 :
1.
SPT에 페이지 정보 등록 
2.
물리 메모리 할당 
3.
데이터 로드 
4.
나중에 lazy_load_segment 함수 호출하도록 등록 
3. 프로그램 실행 중
// 사용자 프로그램(예시)
int main() {
printf("Hello"); // 0x1000 주소 접근!
}
C
복사
4. 페이지 폴트 발생
userprog/exception.c
// 실제로는 인터럽트 프레임을 인자로 전달받음
page_fault(0x1000) {
// 핀토스 코드의 두 번째 인자(fault_addr)
vm_try_handle_fault(..., 0x1000, ...);
}
C
복사
5. vm_try_handle_fault
vm/vm.c
bool vm_try_handle_fault(struct intr_frame *f, void *addr, bool user,
bool write, bool not_present) {
struct supplemental_page_table *spt = &thread_current()->spt;
struct page *page = NULL;
/* TODO: Validate the fault */
/* TODO: Your code goes here */
return vm_do_claim_page(page);
}
C
복사
TODO 주석에 의하면(우리가 구현해야함) :
1. SPT에서 해당하는 페이지 찾기
2. 페이지 검증 작업
3. 페이지 클레임(실제 로딩)
6. vm_do_claim_page
static bool vm_do_claim_page(struct page *page) {
struct frame *frame = vm_get_frame();
frame->page = page;
page->frame = frame;
/* TODO: Insert page table entry to map page's VA to frame's PA. */
return swap_in(page, frame->kva);
}
C
복사
TODO 주석에 의하면(우리가 구현해야함) :
1. 물리 프레임 할당
2. 연결
3. 실제 데이터 로딩(스왑-인)
7. uninit_initialize (자동 호출)
vm/uninit.c
static const struct page_operations uninit_ops = {
.swap_in = uninit_initialize,
.swap_out = NULL,
.destroy = uninit_destroy,
.type = VM_UNINIT,
};
C
복사
이렇게 연산 함수와 swap_in 인자가 매핑되어있습니다. 어느 지점에서 이게 매핑된 건지는 아직 모르겠습니다.
아무튼 uninit_initialize 함수와 swap_in이 매핑되어있다보니, vm_do_claim_page 함수에서 swap_in을 호출할 때, uninit_initialize 함수가 자동으로 호출됩니다.
struct uninit_page {
/* Initiate the contets of the page */
vm_initializer *init;
enum vm_type type;
void *aux;
/* Initiate the struct page and maps the pa to the va */
bool (*page_initializer) (struct page *, enum vm_type, void *kva);
};
C
복사
uninit_initialize (struct page *page, void *kva) {
struct uninit_page *uninit = &page->uninit;
/* Fetch first, page_initialize may overwrite the values */
vm_initializer *init = uninit->init;
void *aux = uninit->aux;
/* TODO: You may need to fix this function. */
return uninit->page_initializer (page, uninit->type, kva) &&
(init ? init (page, aux) : true);
}
C
복사
TODO 주석에 의하면(우리가 구현할 내용) :
페이지에 저장된 정보들이 꺼내진 상태에서,
1. init 함수를 호출하기
우리가 2단계(vm_alloc_page_with_initializer 함수가 실행되는 시점)에서 lazy_load_segment 함수를 콜백함수로 등록해뒀습니다. 그래서 init 함수를 실행하는 시점에, lazy_load_segment 함수를 호출합니다.
8. lazy_load_segment
userprog/process.c
static bool lazy_load_segment(struct page* page, void* aux) {
/* TODO: Load the segment from the file */
/* TODO: This called when the first page fault occurs on address VA. */
/* TODO: VA is available when calling this function. */
}
C
복사
TODO 주석에 의하면(우리가 구현할 내용) :
1. 파일 정보를 꺼내기
2. 파일에서 정보를 읽고, 정보를 file에 저장?
9. VM_UNINIT → VM_ANON 변환
struct uninit_page {
/* Initiate the contets of the page */
vm_initializer *init;
enum vm_type type;
void *aux;
/* Initiate the struct page and maps the pa to the va */
bool (*page_initializer) (struct page *, enum vm_type, void *kva);
};
C
복사
enum vm_type {
/* page not initialized */
VM_UNINIT = 0,
/* page not related to the file, aka anonymous page */
VM_ANON = 1,
/* page that realated to the file */
VM_FILE = 2,
/* page that hold the page cache, for project 4 */
VM_PAGE_CACHE = 3,
// 이하 생략...
};
C
복사
static bool
uninit_initialize (struct page *page, void *kva) {
struct uninit_page *uninit = &page->uninit;
/* Fetch first, page_initialize may overwrite the values */
vm_initializer *init = uninit->init;
void *aux = uninit->aux;
/* TODO: You may need to fix this function. */
return uninit->page_initializer (page, uninit->type, kva) &&
(init ? init (page, aux) : true);
}
C
복사
uninit 페이지를 init 함수의 인자로 전달하면서 초기화하는 과정 중에 vm_type이 VM_ANON으로 변환됩니다.

