어떤 가상/물리 메모리가 있을 때, 이 메모리가 사용되고 있는지, 목적은 무엇인지, 누구에 의해 사용되는지 등등, 메모리를 트랙킹할 수 있는 환경을 먼저 구축한다.
이를 위해 큰 목표 2가지를 세운다.
Step 1 : Supplemental Page Table 구현
페이지에 대한 모든 정보를 담고 있는 구조체이다.
<aside> 💡 struct page 자체가 페이지는 아니다. 다만, 유저 가상 메모리에 우리가 만들어준 페이지를 관리해주기 위해 프로세스의 커널 주소 영역에 선언해준 구조체이다. 유저 가상 메모리 내 페이지의 실제 주소는 page->va에 있다.
</aside>
include/vm/vm.h
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
};
};
구성 요소
page_operations : 페이지에 관련한 작업들
va : 페이지의 가상 메모리 주소
frame : 할당된 물리 메모리 프레임 주소
union
struct는 각 멤버들마다 다른 메모리 공간을 가지지만, union은 멤버들 중 가장 큰 크기를 갖는 멤버만큼의 메모리를 지니면서 모든 멤버가 같은 메모리 공간을 공유한다(참조).
해당 페이지의 유형이 uninitialized page인지, anonymous page인지, file-backed page인지 혹은 page cache인지 나타낸다.
해당 페이지가 가지고 있는 연산의 종류를 나타내는 필드이다. struct thread
안의 필드로 들어가 있다. 현재 크게 세 가지 연산이 존재하는데, 차례대로 swap_in
, swap_out
, destroy
이다. 해당 페이지가 어떤 타입을 가지고 있느냐에 따라 해당 연산을 실제로 수행하는 함수들이 달라진다.
함수 포인터를 활용하여 각 페이지 유형에 맞는 연산을 수행할 것이다.
vm.h/struct page_operations
struct page_operations {
bool (*swap_in) (struct page *, void *);
bool (*swap_out) (struct page *);
void (*destroy) (struct page *);
enum vm_type type;
};
#define swap_in(page, v) (page)->operations->swap_in ((page), v)
#define swap_out(page) (page)->operations->swap_out (page)
#define destroy(page) \\
if ((page)->operations->destroy) (page)->operations->destroy (page)