SW 사관학교 정글(Jungle)/운영체제-PintOS

[PintOS Project 3 - VIRTUAL MEMORY] Memory management 구현 중.. 간단한 예시로 흐름 파악하기(사용자가 arr[1024]를 요구했다면!)

jinsang-2 2024. 10. 12. 11:28

실제 우리 프로젝트에서 사용한 코드는 아니다. 전체적 흐름만 파악하기 위한 코드

 

(참고) 현재 vm_entry 버리고 page 구조체에 spt로 관리

전체 흐름 요약

1. 사용자 가상 주소 (UVA) 0x80400000에 배열이 선언됨.
2. vm_entry가 생성되어 가상 메모리 페이지 정보를 관리.
3. 배열에 처음 접근할 때 페이지 폴트 발생.
4. vm_claim_page가 호출되어 해당 가상 주소를 물리 메모리로 매핑.
5. 프레임을 할당받아 페이지 테이블을 통해 UVA와 KVA 및 물리 주소를 매핑.
6. 배열이 물리 메모리에 할당되고, CPU는 페이지 테이블을 통해 물리 메모리에 접근.

 

1. 배열 선언 (arr[1024])과 가상 주소 할당

배열을 선언하면, 컴파일러는 배열을 위한 메모리 공간을 가상 주소 공간에서 할당합니다. 이 공간은 UVA 0x80400000으로 매핑될 수 있습니다. 하지만, 이 시점에서 아직 물리 메모리에는 실제로 할당된 페이지가 없습니다.

 

int arr[1024];  // arr는 UVA 0x80400000에 위치한다고 가정

 

2. vm_entry와 page 생성

프로세스가 배열을 사용하려고 시도할 때, 가상 주소에 해당하는 페이지를 메모리에 로드하기 위해 vm_entry가 만들어집니다.

vm_entry는 이 페이지에 대한 메타데이터를 저장하는 구조체입니다. 페이지가 아직 메모리에 로드되지 않았을 수 있으므로 is_loaded 필드는 false로 설정됩니다.

 

👇vm_entry 생성 코드 예시

struct vm_entry *vme = palloc_get_page(0);  // vm_entry 메모리 할당
vme->type = VM_ANON;                        // 익명 페이지
vme->vaddr = 0x80400000;                    // 가상 주소
vme->writable = true;                       // 쓰기 가능
vme->is_loaded = false;                     // 아직 물리 메모리에 로드되지 않음
vme->file = NULL;                           // 파일 매핑 없음
vme->offset = 0;                            // 파일 오프셋 없음
vme->read_bytes = PGSIZE;                   // 읽을 바이트 수
vme->zero_bytes = 0;                        // 0으로 초기화할 바이트 수
vme->swap_slot = -1;                        // 스왑 슬롯 (초기 상태)
insert_vme(&thread_current()->spt.vm, vme); // vm 해시 테이블에 삽입

이 코드에서 vm_entry는 가상 주소 UVA 0x80400000이 속한 페이지에 대한 정보를 관리합니다.

3. 페이지 폴트 발생

배열 arr에 접근하려고 할 때, 해당 가상 주소(예: 0x80400000)에 대응하는 페이지가 아직 물리 메모리에 로드되지 않은 상태이므로, 페이지 폴트가 발생합니다.

 

👇페이지 폴트 처리

page_fault_handler(...){
    // 폴트 난 주소를 확인 (여기서는 0x80400000)
    void *fault_addr = get_fault_addr();
    
    // 해당 주소에 대한 vm_entry 검색
    struct vm_entry *vme = find_vme(fault_addr);

    if (vme == NULL) {
        // 주소에 대한 vm_entry가 없다면, 접근 오류 처리
        exit(-1);
    }

    if (!vme->is_loaded) {
        // 페이지가 아직 물리 메모리에 로드되지 않은 경우
        vm_claim_page(vme->vaddr);  // 페이지를 물리 메모리로 로드
    }
}

4. 페이지 테이블 설정 (vm_claim_page)

페이지 폴트가 발생하면, 해당 가상 주소에 대한 페이지를 물리 메모리로 할당해야 합니다. 이를 위해 vm_claim_page() 함수가 호출됩니다. 이 함수는 가상 주소를 물리 메모리의 프레임에 매핑하는 역할을 합니다.

 

👇vm_claim_page 호출

bool vm_claim_page(void *vaddr) {
    struct page *page = page_lookup(vaddr);  // 해당 주소에 대한 페이지 검색
    if (page == NULL) {
        return false;  // 페이지가 없으면 실패 처리
    }
    return vm_do_claim_page(page);  // 페이지를 실제로 할당
}

 

5. 물리 메모리 프레임 할당 (vm_do_claim_page)

vm_do_claim_page() 함수는 실제로 페이지를 물리 메모리에 매핑하고, 이를 페이지 테이블에 반영하는 역할을 합니다. 이 함수에서 물리 메모리의 프레임을 할당받고, 이를 가상 주소에 매핑합니다.

 

👇프레임 할당 및 페이지 테이블 매핑

bool vm_do_claim_page(struct page *page) {
    // 1. 새로운 물리 프레임 할당
    struct frame *f = vm_get_frame();
    if (f == NULL) {
        PANIC("Frame allocation failed!");
    }
    
    // 2. 페이지와 프레임을 연결
    f->page = page;
    page->frame = f;

    // 3. 페이지 테이블에 가상 주소와 물리 주소를 매핑
    if (!install_page(page->vaddr, f->kva, page->writable)) {
        // 매핑 실패 시 처리
        PANIC("Page mapping failed!");
    }

    // 4. 페이지가 물리 메모리에 로드되었음을 표시
    page->vme->is_loaded = true;

    return true;  // 성공적으로 페이지 할당
}

6. 페이지 테이블 매핑 완료

install_page() 함수는 페이지 테이블을 업데이트하여 가상 주소와 물리 메모리의 프레임을 연결합니다.

 

👇페이지 테이블 매핑

bool install_page(void *vaddr, void *kva, bool writable) {
    // 페이지 테이블에 가상 주소(vaddr)를 커널 가상 주소(kva)에 매핑
    return pagedir_set_page(thread_current()->pagedir, vaddr, kva, writable);
}

7. 물리 메모리에서 배열에 접근

이제 UVA 0x80400000에 해당하는 가상 페이지가 물리 메모리로 매핑되었으므로, 배열 arr[0]에 접근할 수 있습니다. 이때, CPU는 페이지 테이블을 사용하여 UVA에서 물리 주소로 변환을 수행합니다.