[Pintos] - Virtual Memory - (Memory Management)

Junyeong Fred Kim·2022년 1월 19일
0

운영체제

목록 보기
18/27

Memory Management

가상 메모리 시스템을 지원하려면 virtual pagesphysical frames을 효과적으로 관리한다. 즉, 사용 중인 (virtual or physical) 메모리 영역, 용도, 사용자 등을 추적해야 한다. 먼저 supplemental page table을 처리하고 그 다음 실제 프레임을 처리한다. 참고로 virtual page에는 "page"라는 용어를 사용하고 physical page에는 "frame"이라는 용어를 사용한다.

Page Structure and Operations

🥞 struct page

include/vm/vm.h에 정의된 page는 가상 메모리에 있는 페이지를 나타내는 구조이다. 그것은 우리가 페이지에 대해 알아야 할 모든 필요한 데이터를 저장한다. 현재 구조는 템플릿에서 다음과 같다.

struct page {
  const struct page_operations *operations;
  void *va;              /* Address in terms of user space */
  struct frame *frame;   /* Back reference for frame */

  union {
    struct uninit_page uninit;
    struct anon_page anon;
    struct file_page file;
#ifdef EFILESYS
    struct page_cache page_cache;
#endif
  };
};

Union에는 여러 명의 구성원이 있지만 한 번에 한 명의 구성원만 값을 포함할 수 있다.

즉, 시스템의 페이지는 uninit_page, anon_page, file_page 또는 page_cache일 수 있다.

Page Operations

위에서 설명하고 include/vm/vm.h에서 정의한 대로 페이지는 VM_UNINIT, VM_ANON 또는 VM_FILE일 수 있습니다. 페이지에는 swapping in, swapping out, destroying 등의 여러 가지 작업이 있다. 페이지 유형마다 이러한 작업에 필요한 단계와 태스크가 다르다. 즉, VM_ANON 페이지와 VM_FILE 페이지에 대해 다른 destroy 함수를 호출해야 한다. 한 가지 방법은 각 함수에서 스위치 케이스 구문을 사용하여 각 케이스를 처리하는 것. 그것을 다루기 위해 객체 지향 프로그래밍의 "클래스 상속" 개념을 도입한다.

실제로, C 프로그래밍 언어에는 클래스나 상속이 없으며, 리눅스와 같은 실제 운영 체제 코드에서도 비슷한 방식으로 개념을 실현하기 위해 함수 포인터를 사용한다.

함수 포인터는 지금까지 배운 다른 포인터들처럼 메모리 내의 함수나 실행 가능한 코드를 가리키는 포인터이다. 함수 포인터는 검사 없이 런타임 값을 기반으로 특정 함수를 호출하여 실행할 수 있는 간단한 방법을 제공하기 때문에 유용하다. 우리의 경우 코드 레벨에서 단순히 destroy(page)를 호출하는 것으로 충분하며 컴파일러는 올바른 함수 포인터를 호출함으로써 페이지 유형에 따라 적절한 destroy 루틴을 선택한다. (뭔말이야)

페이지 작업 구조 page_operations의 구조는 include/vm/vm.h에 정의되어 있다. 이 구조를 3개의 함수 포인터를 포함하는 함수 테이블로 간주한다.

struct page_operations {
  bool (*swap_in) (struct page *, void *);
  bool (*swap_out) (struct page *);
  void (*destroy) (struct page *);
  enum vm_type type;
};

이제 page_operation 구조를 어디서 찾을 수 있는지 알아보자. include/vm/vm.hstruct page를 들여다보면 operations라는 필드가 있다. 이제 vm/file.c로 이동하면 page_operations structure file_ops가 함수 프로토타입보다 먼저 선언된 것을 볼 수 있다. .destroy 필드는 페이지를 destroy하고 같은 파일에 정의되는 함수인 file_backed_destroy 값을 가지고 있다.

file_backed_destroy가 함수 포인터 인터페이스로 어떻게 호출되는지 알아보자. vm_deloc_page(page)(in vm/vm.c)가 호출되었는데 이 페이지가 file-bakced page (VM_FILE)라고 가정한다. 함수 내에서 destroy(page)를 호출합니다. destroy(page)는 다음과 같이 include/vm/vm.h의 매크로로 정의된다.

#define destroy(page) if ((page)->operations->destroy) (page)->operations->destroy (page)

이것은 destroy 함수를 호출하는 것이 실제로 page structure에서 검색되는 destroy 함수인 (page)->operations->destroy (page)를 호출함을 알려준다. 페이지는 VM_FILE 페이지이므로 .destroy 필드는 file_backed_destory를 가리킨다. 따라서 파일 백업 페이지에 대한 삭제 루틴이 수행됨.


Implement Supplemental Page Table

이때 Pintos는 메모리의 가상 및 물리적 매핑을 관리하기 위한 페이지 테이블(pml4)을 갖게 된다. 하지만 이것만으로는 충분하지 않다. 이전 섹션에서 논의한 것처럼 페이지 오류 및 리소스 관리를 처리하기 위해 각 페이지에 대한 추가 정보를 저장할 수 있는 추가 페이지 표도 필요하다. 따라서 project3의 첫 번째 작업으로 supplemental page table에 대한 몇 가지 기본 기능을 구현할 것.


void supplemental_page_table_init (struct supplemental_page_table *spt);

void supplemental_page_table_init (struct supplemental_page_table *spt);
  • supplemental page table 초기화.
  • supplemental page table함수는 프로세스가 시작될 때 호출된다.

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

struct page *spt_find_page (struct supplemental_page_table *spt, void *va);
  • supplemental page table에서 va에 해당하는 구조체 페이지를 찾는다. 실패하면 NULL을 반환.

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

bool spt_insert_page (struct supplemental_page_table *spt, struct page *page);
  • struct page를 supplemental_page_table에 insert.
  • 이 함수는 supplemental_page_tableva가 없는지 확인해야한다.

Frame Management

이제, 모든 페이지는 단지 메타데이터가 구성되었을 때 메모리에 대한 데이터만 보유하고 있는 것이 아니다. 따라서 물리적 메모리를 관리하기 위해서는 다른 방식이 필요하다. include/vm/vm.h에는 물리적 메모리를 나타내는 struct frame이 존재한다. 현재 구조는 아래와 같다.

/* The representation of "frame" */
struct frame {
  void *kva;
  struct page *page;
};

현재는 kernel virtual address인 kva와 page structure인 page의 두 필드만 있지만, 프레임 관리 인터페이스를 구현할 때 추가할 수 있다.

Implement vm_get_frame, vm_claim_page and vm_do_claim_page in vm/vm.c.


static struct frame *vm_get_frame (void);

static struct frame *vm_get_frame (void);
  • paloc_get_page를 호출하여 user pool에서 새로운 physical page를 가져온다.
  • user pool에서 할당이 성공했다면, frame을 할당 받고 member를 초기화하고 return한다.
  • vm_get_frame을 구현한 후에는 이 함수를 통해 모든 사용자 공간 페이지(PALOC_USER)를 할당해야 한다.
  • page allocation 실패 시 일단은 swap out을 처리하지 않아도 된다. 일단 그 케이스에 PANIC("todo")으로 표시.

bool vm_do_claim_page (struct page *page);

bool vm_do_claim_page (struct page *page);
  • claim, 즉, physical frame을 할당 받는 것.
  • 먼저 vm_get_frame을 호출하여 프레임을 얻는다. (이미 템플릿에서 완료)
  • 그런 다음 MMU를 설정
  • 가상 주소에서 페이지 테이블의 물리 주소로 매핑을 추가.
  • return 값은 작업이 성공했는지 여부를 나타낸다. true/false

bool vm_claim_page (void *va);

bool vm_claim_page (void *va);
  • va를 할당하기 위해 페이지를 요청.
  • 먼저 페이지를 받은 후, 페이지와 함께 vm_do_claim_page를 호출
profile
기억보다 기록

0개의 댓글