현재 핀토스에서는 레벨 4 페이지 테이블(pml4)을 사용하여 가상 메모리 주소와 물리 메모리 주소 간의 매핑 정보를 저장한다. 하지만 이것만으로는 충분하지 않다. Supplemental Page Table을 구현해 페이지에 대한 추가적인 정보들을 저장하게 되면 Page Fault와 Resource Management를 수월하게 진행할 수 있다.
supplemental page table은 기존의 page table을 보완하기 위해 만든 것이다.
역할
크게 두 가지 역할을 수행한다.
struct supplemental_page_table 구현
먼저 추가 페이지 테이블의 구조체 struct supplemental_page_table을 구현한다. 그 후에 추가 테이블 구조체에 관계된 함수를 구현한다.
Supplemental page table을 구현하는 방식은 여러 가지가 있을 수 있다. 배열이나, 비트맵, 해시 테이블도 가능하다. hash table로 구현하자.
frame table은 물리 메모리 내의 각 프레임의 정보를 갖고 있다.
역할
Frame table은 frame entry의 리스트로 구성되는데,
각 엔트리는 물리 메모리 프레임 테이블로 인해 eviction 정책, 즉 SWAP OUT/IN을 위한 프레임 교체 정책을 수행할 수 있게 된다.
struct frame_table 구현
1-1. hash.h include
#define VM_VM_H
#include <stdbool.h>
#include "threads/palloc.h"
#include <hash.h> /** Project 3-Memory Management */
...
1-2. spt_hash 추가
supplemental_page_table에 hash 구조체를 추가한다.
struct supplemental_page_table {
struct hash spt_hash; /** Project 3-Memory Management */
};
1-3. hash_elem 추가
page 구조체에 hash_elem을 추가한다.
struct page {
const struct page_operations *operations;
void *va; /* Address in terms of user space */
struct frame *frame; /* Back reference for frame */
/* Your implementation */
/* Per-type data are binded into the union.
* Each function automatically detects the current union */
union {
struct uninit_page uninit;
struct anon_page anon;
struct file_page file;
#ifdef EFILESYS
struct page_cache page_cache;
#endif
};
/** Project 3-Memory Management */
struct hash_elem hash_elem;
};
2. supplemental_page_table_init() 구현
void
supplemental_page_table_init (struct supplemental_page_table *spt UNUSED) {
/** Project 3-Memory Management */
hash_init(spt, page_hash, page_less, NULL);
}
3. page_hash() 구현
3-1. 선언
/** Project 3-Memory Management */
uint64_t page_hash(const struct hash_elem *e, void *aux);
3-2. 구현
/** Project 3-Memory Management */
uint64_t
page_hash(const struct hash_elem *e, void *aux)
{
struct page *page = hash_entry(e, struct page, hash_elem);
return hash_bytes(page->va, sizeof *page->va);
}
4. page_less() 구현
4-1. 선언
/** Project 3-Memory Management */
uint64_t page_hash(const struct hash_elem *e, void *aux);
bool page_less(const struct hash_elem *a, const struct hash_elem *b, void *aux);
4-2. 구현
/** Project 3-Memory Management */
bool
page_less(const struct hash_elem *a, const struct hash_elem *b, void *aux)
{
struct page *page_a = hash_entry(a, struct page, hash_elem);
struct page *page_b = hash_entry(b, struct page, hash_elem);
return page_a->va < page_b->va;
}
5. spt_find_page() 구현
supplementary page table에서 va에 해당하는 구조체 페이지를 찾아 반환한다.
struct page *
spt_find_page (struct supplemental_page_table *spt UNUSED, void *va UNUSED) {
/** Project 3-Memory Management */
struct page *page = (struct page *)malloc(sizeof(struct page));
page->va = pg_round_down(va);
struct hash_elem *e = hash_find(&spt->spt_hash, &page->hash_elem);
free(page);
return e != NULL ? hash_entry(e, struct page, hash_elem) : NULL;
}
6. spt_insert_page() 구현
bool
spt_insert_page (struct supplemental_page_table *spt UNUSED,
struct page *page UNUSED) {
/** Project 3-Memory Management */
return hash_insert(&spt->spt_hash, &page->hash_elem) ? false : true;
}
7-1. frame_table 추가 및 초기화
/* vm.c: Generic interface for virtual memory objects. */
#include "threads/malloc.h"
#include "vm/vm.h"
#include "vm/inspect.h"
/** Project 3-Memory Management */
static struct list frame_table;
/* Initializes the virtual memory subsystem by invoking each subsystem's
* intialize codes. */
void
vm_init (void) {
vm_anon_init ();
vm_file_init ();
#ifdef EFILESYS /* For project 4 */
pagecache_init ();
#endif
register_inspect_intr ();
/* DO NOT MODIFY UPPER LINES. */
/** Project 3-Memory Management */
list_init(&frame_table);
}
7-2. frame_elem 추가
struct frame {
void *kva;
struct page *page;
/** Project 3-Memory Management */
struct list_elem frame_elem;
};
8. vm_get_frame() 구현
static struct frame *
vm_get_frame (void) {
struct frame *frame = NULL;
/* TODO: Fill this function. */
/** Project 3-Memory Management */
struct frame *frame = (struct frame *)malloc(sizeof(struct frame));
ASSERT (frame != NULL);
frame->kva = palloc_get_page(PAL_USER | PAL_ZERO);
if (frame->kva == NULL)
frame = vm_evict_frame();
else
list_push_back(&frame_table, &frame->frame_elem);
frame->page = NULL;
ASSERT (frame->page == NULL);
return frame;
}
9. vm_claim_page() 구현
bool
vm_claim_page (void *va UNUSED) {
struct page *page = NULL;
/** Project 3-Memory Management */
struct page *page = spt_find_page(&thread_current()->spt, va);
if (page == NULL)
return false;
return vm_do_claim_page (page);
}
10. vm_do_claim_page() 구현
10-1. writable 구조체 추가
struct page {
const struct page_operations *operations;
void *va; /* Address in terms of user space */
struct frame *frame; /* Back reference for frame */
/* Your implementation */
/* Per-type data are binded into the union.
* Each function automatically detects the current union */
union {
struct uninit_page uninit;
struct anon_page anon;
struct file_page file;
#ifdef EFILESYS
struct page_cache page_cache;
#endif
};
/** Project 3-Memory Management */
struct hash_elem hash_elem;
bool writable;
};
10-2. mmu.h include
/** Project 3-Memory Management */
#include "threads/mmu.h"
static struct list frame_table;
10-3. vm_do_claim_page() 구현
vm/vm.c
static bool
vm_do_claim_page (struct page *page) {
struct frame *frame = vm_get_frame ();
/* Set links */
frame->page = page;
page->frame = frame;
if (!pml4_set_page(thread_current()->pml4, page->va, frame->kva, page->writable))
return false;
return swap_in (page, frame->kva);
}
10-3. vm_do_claim_page() 구현
static bool
vm_do_claim_page (struct page *page) {
struct frame *frame = vm_get_frame ();
/* Set links */
frame->page = page;
page->frame = frame;
if (!pml4_set_page(thread_current()->pml4, page->va, frame->kva, page->writable))
return false;
return swap_in (page, frame->kva);
}
아놔