[WIL] PintOS_project_3(temp)

김현태·2023년 5월 10일
0
post-thumbnail

<Memory management>

supplementary page table 설계

  • supplementary page table(spt)
    : 보조 데이터들을 담고 있는 프로세스마다 존재하는 자료구조
    보조 데이터는 각각의 페이지에 대해 데이터가 존재하는 곳(frame, disk, swap), 이에 상응하는 커널 가상주소를 가리키는 포인터 정보(active, inactive) 등이 있다.

  • spt의 용도
    1. page fault 발생 시 그곳에 어떤 데이터가 있었어야 했는지 알아내기 위해 spt에서 fault가 발생한 가상 페이지를 탐색
    2. 커널이 프로세스가 종료될 때 어떤 자원을 해제(free)할 지 고르기 위해 spt를 조사

  • 구현해야 할 것

void supplemental_page_table_init (struct supplemental_page_table *spt);

  spt를 초기화하는 함수. 어떤 자료구조로 구현할 지는 선택(배열, 리스트, 비트맵, 해시)
userprog/process.cinitd, __do_fork 함수에서 새로운 프로세스가 생성될 때 이 함수가 호출된다.

struct page *spt_find_page (struct supplemental_page_table *spt, void *va);

  spt로부터 가상주소 va와 대응되는 페이지 구조체를 찾아서 반환, 실패 시 NULL을 반환한다.

bool spt_insert_page (struct supplemental_page_table *spt, struct page *page);

  spt에 page를 삽입, spt에 가상주소가 존재하지 않는 것을 확인해야한다.

frame management

include/vm/vm.h 에 물리 메모리를 뜻하는 struct frame이 선언되어 있다. 이 구조체는 다음과 같은 모습이다.

struct frame {
  void *kva;			/* 커널 가상 주소 */
  struct page *page;	/* 페이지 구조체를 담기 위한 멤버 */
};

  frame 관리 인터페이스를 구현하는 과정에서 멤버 추가를 할 수도 있다.

static struct frame *vm_get_frame (void);

  palloc_get_page() 해서 새로운 물리메모리 페이지를 가져온 후 프레임을 할당하고, 프레임 구조체의 멤버를 초기화하고 해당 프레임을 반환한다.
 이 함수를 구현한 이후에는 모든 유저공간 페이지 할당 시 이 함수를 이용해야 한다.
 일단은 페이지 할당 실패 시 swap out 구현하지 말고 PANIC("TODO")로 표시만 해둔다.

bool vm_do_claim_page (struct page *page);

  page에 물리 프레임을 할당해준다.

bool vm_claim_page (void *va);

  va에 페이지를 할당하고, 해당 페이지에 프레임을 할당해준다.

<Anonymous Page>

  • file_backed page와 달리 이름이 있는 파일 소스를 가지고 있지 않기 때문에 anonymous(익명).
  • 커널로부터 할당되었다.
  • 디스크에 있던 프로그램이 실행될 때 코드 영역과 데이터 영역은 메모리에 file-backed page로 load되지만 스택, 힙 영역은 anonymous page로 메모리에 할당된다.
  • include/vm/anon.hstruct anon_page가 선언되어 있다. 비어 있으므로 구현 도중 필요한 정보나 상태 멤버를 추가.

Page Initialization with Lazy Loading

  • Lazy loading : 필요 시점까지 메모리의 load를 지연시키는 방법.
  • page allocation은 대응되는 페이지 구조체는 있지만 연결된 프레임은 아직 없고 페이지에 대한 실제 content가 아직 load되지 않았다는 것을 의미한다.
  • content들은 page fault로 인해 정말로 content가 필요하다는 signal을 받을 때 load된다.

페이지의 3가지 타입(uninit, anonymous, file_backed)별로 initialization routine이 다르다.

  1. 커널이 새로운 페이지를 달라는 요청을 받으면 vm_alloc_page_with_initializer 호출
  2. initializer 함수는 페이지 구조체를 할당하고 페이지 타입에 맞는 초기화 함수를 세팅함으로써 새로운 페이지를 초기화하고 유저 프로그램으로 제어권을 넘김
  3. 유저 프로그램이 실행될 때, Lazy loading으로 인해 아직 Load가 일어나지 않은 페이지에 접근하게 되어 page fault가 일어난다.
  4. 이 page fault를 handling 하는 과정에서 uninit_initialize를 호출하고 세팅된 초기화 함수를 호출한다.
  5. anonymous page를 위한 초기화 함수는 anon_initializer이고, file_backed page를 위한 초기화 함수는 file_backed_initializer이다.

페이지는 initialize -> (page fault -> lazy loading -> swap in -> swap out -> ...) -> destroy의 생명 주기를 갖는다. 이 주기의 각 상태 변화마다 페이지 타입별로 다른 프로시저가 요구된다. 이번 프로젝트에서 각 페이지 타입별로 다른 상태 변화의 과정을 구현해야 한다.

Lazy Loading for Executable

  • Lazy loading에서는 프로세스가 실행될 때 당장 필요한 메모리의 부분만 메인 메모리에 로드된다.
  • Lazy loading은 동시에 모든 binary image들을 로드하는 eager loading보다 오버헤드를 더 줄일 수 있다.

VM_UNINIT

: 모든 페이지들은 초기에 VM_UNINIT 타입의 페이지로 생성된다. include/vm/uninit.hstruct uninit_page 구조체가 선언되어 있다. uninit_page를 생성, 초기화, 제거하는 함수들은 vm/vm.c에서 찾을 수 있다. 추후 이 함수들을 완성해야 한다.

Page Fault Handler

  • page fault가 일어나면, page fault handler는 vm_try_handle_fault 함수에게 제어권을 넘기고 이 함수는 우선 유효한 page fault인지 검사한다.
  • lazy loading으로 인해 content가 아직 로드되지 않은 경우의 page fault라면(bogus fault), 페이지에 content를 로드하고 유저 프로그램에 제어를 돌려준다.

Three Cases of Bogus Page Fault

  1. lazy-loaded page
  2. swapped-out page
  3. write-protected page

Lazy-loaded Page

 lazy-loading 때문에 page fault가 일어나면 커널은 segment를 지연 로딩하기 위해 vm_alloc_page_with_initializer 함수에서 세팅해 놓은 초기화 함수를 호출한다.
userprog/process.c에 있는 lazy_load_segment 함수를 구현해야 한다.

bool vm_alloc_page_with_initializer (enum vm_type type, void *va,
        bool writable, vm_initializer *init, void *aux);

 인자로 주어진 type으로 uninitialized page를 생성한다. uninit 페이지의 swap_in 핸들러는 페이지 타입에 맞게 페이지를 초기화하고 주어진 AUX를 인자로 삼는 INIT 함수를 호출한다.
 페이지 구조체를 가지게 되면 프로세스의 spt에 그 페이지를 삽입해야 한다. vm.h에 정의되어 있는 VM_TYPE 매크로를 사용하면 편리할 것이다.

page fault 핸들러는 연쇄적으로 함수를 호출하고 swap_in 함수를 호출하면 마침내 uninit_initialize 함수에 다다르게 된다. 이 함수는 이미 작성되어 있지만 필요하면 수정해도 된다.

static bool uninit_initialize (struct page *page, void *kva);

이 함수는 처음으로 fault가 발생한 페이지를 초기화 시킨다. 먼저 uninit_page의 멤버 변수인 vm_initializer, aux를 가져온 후 page_initializer를 함수 포인터로 호출한다. 이 함수를 수정해야한다.

void vm_anon_init(void);

anonymous page의 하위 시스템을 초기화한다. 필요한 것들 셋업

bool anon_initializer (struct page *page,enum vm_type type, void *kva);

처음으로 page->operation에 있는 anonymous page에 대한 핸들러를 설정하여준다. 비어있는 구조체인 anon_page의 정보들을 업데이트 할 필요가 있음.

userprog/process.c에 있는 load_segmentlazy_load_segment를 구현해야 한다. 실행파일로부터 세그먼트가 로드되는 것을 구현하고 이러한 페이지들은 lazy load가 되어야한다.

프로그램 로더의 핵심인 userprog/process.cload_segment loop 내부를 수정해야 한다. 루프를 돌 떄마다 load_segment는 대기 중인 페이지 오브젝트를 생성하는 vm_alloc_page_with_initializer를 호출한다. Page fault가 발생하는 순간은 세그먼트가 실제로 파일에서 로드될 때이다.

static bool load_segment (struct file *file, off_t ofs, uint8_t *upage,
        uint32_t read_bytes, uint32_t zero_bytes, bool writable);

현재 코드는 메인 루프 안에서 파일로부터 읽을 바이트의 수와 0으로 채워야 할 바이트의 수를 측정한다. 그리고 그것은 대기 중인 오브젝트를 생성하는 vm_alloc_page_with_initializer 함수를 호출한다. vm_alloc_page_with_initializer에 재공할 aux 인자로써 보조 값들을 설정할 필요가 있다. 바이너리 파일을 로드할 때 필수적인 정보를 포함하는 구조체를 생성하는 것이 좋다.

0개의 댓글

관련 채용 정보