jun-wiki

View My GitHub Profile

Posts (Latest 10 updated) :
Read all
Contents:
  1. 프로젝트3: 가상 메모리
    1. 메모리 관리 (Memory Management)
    2. 페이지 구조와 연산 (Page Structure and Operations)
      1. struct page
    3. 페이지 연산 (Page Operations)
    4. struct page_operations
    5. 함수 포인터를 통한 호출 과정 예시
    6. 보조 페이지 테이블 구현 (Implement Supplemental Page Table)
    7. 설계
    8. 프레임 관리 (Frame Management)
    9. 구현해야 할 함수들

프로젝트3: 가상 메모리

메모리 관리 (Memory Management)

가상 메모리 시스템을 위해 가상 페이지와 물리 프레임을 효과적으로 관리해야한다

어떤 메모리 영역이 사용되고, 왜 사용되며, 누가 사용하는지를 추적해야 한다는 뜻이다

보조 페이지 테이블 먼저 다루고 물리 프레임 다룬다고 한다

헷갈리니 단어 의미 통일 한다고 한다

  • 페이지 : 가상 페이지

  • 프레임 : 물리 페이지


페이지 구조와 연산 (Page Structure and Operations)

struct page

include/vm/vm.h에 정의된 struct page는 가상 메모리에서 하나의 페이지를 나타내는 구조체

여기에 페이지에 대해 우리가 알아야 할 모든 필요 데이터 저장한다

템플릿의 현재 구조체란다

struct page {
  const struct page_operations *operations;
  void *va;              /* 사용자 공간 관점의 주소 */
  struct frame *frame;   /* 프레임에 대한 역참조 */

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

이는 페이지 연산, 가상 주소, 물리 프레임을 가진다

추가적으로 union 필드가 존재하는데 union은 특별한 데이터 타입으로, 하나의 메모리 영역에 서로 다른 타입의 데이터를 저장할 수 있게 한다

union에는 여러 멤버가 존재하지만 동시에 하나의 멤버만 값을 가질 수 있다

코드 보면 나오듯 시스템에서 하나의 페이지가 uninit_page, anon_page, file_page, 또는 page_cache 중 하나일 수 있음을 의미한다

예시로, 만약 페이지가 익명 페이지라면, struct page는 멤버 중 하나로 struct anon_page anon을 가진다

anon_page는 익명 페이지에 대해 우리가 유지해야 하는 모든 필요한 정보를 포함한다

익명 페이지에 대해서는 여기서 참고


페이지 연산 (Page Operations)

페이지는 VM_UNINIT, VM_ANON, VM_FILE로 정의되고

각 페이지에 대해서는 swap-in, swap-out, destroy 같은 다양한 동작이 수행된다

그치만 페이지의 종류에 따라 동작 절차와 작업이 다르다

페이지 종류에 따라 서로 다른 destroy 함수가 호출되거나 해야 한다

한 가지 방법은 switch-class문을 활용해 각 경우를 처리하는 경우

이는 객체지향 프로그래밍(OOP)의 “클래스 상속(class inheritance)” 개념을 차용한 것이고 C언어에는 클래스도 상속도 없다

그치만 C에는 포인터가 있어 함수 포인터를 사용해 이 개념 구현한다

함수 포인터는 특정 메모리 내의 함수를 가리키는 포인터다

런타임값에 따라 특정 함수 간단히 호출할 수 있도록 해줘 유용하다


struct page_operations

페이지 연산을 위한 구조체는 include/vm/vm.h에 정의되어 있다

이 구조체는 세 개의 함수 포인터를 포함하는 함수 테이블이라 보면 된다

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

이 구조체는 include/vm/vm.h에 있다

vm/file.c보면 page_operations 구조체인 file_ops가 선언되어 있다

이것이 파일 기반 페이지를 위한 함수 포인터 테이블이다


함수 포인터를 통한 호출 과정 예시

file_backed_destroy를 통해 호출 과정 알아보자

만약 vm_deallock_page(page)가 호출되었고 페이지가 파일 기반 페이지 (VM_FILE)라고 가정하면

해당 함수 안에서는 destroy(page)가 호출된다

destoy(page)include/vm/vm.h에 매크로로 정의되어 있다

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

destroy(page)호출은 사실상 (page)->operations->destroy(page)를 의미한다는 걸 알 수 있다

즉, paage->operation->destroy를 가져와 그 함수를 실행한다

이 페이지가 VM_FILE이면 .destroy필드는 file_backed_destroy를 가리킨다

그 결과, 파일 기반 페이지에 대한 destroy 루틴이 실행된다


보조 페이지 테이블 구현 (Implement Supplemental Page Table)

가상-물리 메모리 매핑을 관리하기 위한 페이지 테이블(pml4)이 있으나 이로는 부족하다

페이지 폴트, 리소스 관리를 위해서는 추가 정보가 필요하고

이를 위해 보조 페이지 테이블(supplemental page table, SPT) 을 구현해야 한다

프로젝트 3의 시작은 이걸로 여는게 좋다

vm/vm.c에 보조 페이지 테이블 관리 함수 구현이 목표다


설계

보조 페이지 테이블을 어떤 자료구조로 설계할지 결정하고 다음 세 가지 함수를 구현하면된다

/* 보조 페이지 테이블을 초기화 한다 initd와 __do_fork 시점에 호출된다
 * 새 프로세스 시작과 fork 시점 */
void supplemental_page_table_init (struct supplemental_page_table *spt);

/* 주어진 보조 페이지 테이블에서 가상 주소 va에 대응되는 struct page를 찾는다
 * 실패 시 NULL 반환 */
struct page *spt_find_page (struct supplemental_page_table *spt, void *va);

/* struct page를 주어진 보조 페이지 테이블에 삽입한다
 * 해당 가상 주소 보조 페이지 테이블에 존재 여부 확인해야 한다*/
bool spt_insert_page (struct supplemental_page_table *spt, struct page *page);

딱 보니 해시테이블로 만들면 되겠다


프레임 관리 (Frame Management)

이제 페이지에는 메타 데이터뿐 아니라 실제 메모리 포함하게 된다

물리 메모리 관리를 위해 별도의 체계가 필요하다

include/vm/vm.h에는 물리 메모리 표현하는 struct frame이 존재한다

/* "프레임"의 표현 */
struct frame {
  void *kva;
  struct page *page;
};

보다시피 필드 두 개가 끝이다

  • kva: 커널 가상 주소 (kernel virtual address)

  • page: 대응되는 페이지 구조체

당연하게도 필요에 따라 멤버 더 추가해야 한다


구현해야 할 함수들

vm/vm.c에 다음 함수들을 구현한다

static struct frame *vm_get_frame (void);
  • 사용자 풀에서 palloc_get_page호출해 새 물리 페이지 얻는다

  • 성공 시 프레임 할당 및 멤버들 초기화하여 반환

  • 이 함수 구현 이후에는 모든 사용자 공간 페이지 할당 얘가 해야 한다

  • 페이지 할당 실패 시 지금은 PANIC("todo")처리하면 된다




bool vm_do_claim_page (struct page *page);
  • 페이지를 claim 한다

  • 먼저 vm_get_frame호출해 프레임 얻는다

  • 이후 MMU 설정

    • 가상 주소와 물리 주소 간의 매핑을 페이지 테이블에 추가해야 함
  • 반환값은 성공 여부 나타낸다 (bool)




bool vm_claim_page (void *va);
  • 가상 주소 va에 해당하는 페이지를 claim 한다

  • 우선 spt에서 페이지 가져오고 vm_do_claim_page 호출



GitBOOK 보니 뭐부터 해야할지 알겠다